标签:坐标 宏定义 cst 题目 多少 表示 int 个数 离散
题目大意:\(N\times M\)的点阵,有的点是树木,定义一个空点的度数为正上,正左,正右,正下分别有\(k\)个点的选法
求点阵的总度数.
挺好的一道题,排列组合和数据结构糅合在一块
#include <iostream>
#include <cstdio>
#include <algorithm>
#define lowbit(x) x & -x//宏定义树状数组操作
using std::sort;
using std::min;
const int N = 1e6 + 10;
struct Node{
int x, y;
}a[N];
int n, m, w, k, col;
int c[N][16];
int tmp[N], xcnt[N], ycnt[N], h[N], r[N], bit[N];
inline void ins(int a, int b){
for(; a <= col; a += lowbit(a))
bit[a] += b;
}
inline int ask(int a){
int ans = 0;
for(; a; a -= lowbit(a)){
ans += bit[a];
}
return ans;
}
inline bool cmp1(Node a, Node b){
return a.x < b.x;
}
inline bool cmp2(Node a, Node b){
return a.y < b.y;
}
inline bool cmp3(Node a, Node b){
if(a.x == b.x) return a.y < b.y;
else return a.x < b.x;
}
inline void pre(){
c[0][0] = 1;
for(int i = 1; i <= w; ++i){
c[i][0] = 1;
for(int j = 1; j <= std::min(i, k); ++j){
c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
}
return;
}//二项式定理预处理组合数
inline void disp(){
int tt = 0;
sort(a + 1, a + w + 1, cmp1);
for(int i = 1; i <= w; ++i){
if(i == 1 || a[i].x != a[i - 1].x){
tt++;
}
tmp[i] = tt;
}
for(int i = 1; i <= w; ++i){
xcnt[a[i].x = tmp[i]]++;
}
sort(a + 1, a + w + 1, cmp2);
tt = 0;
for(int i = 1; i <= w; ++i){
if(i == 1 || a[i].y != a[i - 1].y){
tt++;
}
tmp[i] = tt;
}
for(int i = 1; i <= w; ++i){
ycnt[a[i].y = tmp[i]]++;
}
col = tt;//记录树状数组的“n”
return;
}//离散化
int main(){
scanf("%d %d %d", &n, &m, &w);
for(int i = 1; i <= w; ++i){
scanf("%d %d", &a[i].x, &a[i].y);
}
scanf("%d", &k);
pre();
disp();
sort(a + 1, a + w + 1, cmp3);
int tt = 0, ans = 0;
for(int i = 1, lh, lv; i <= w; ++i){//核心代码
if(i == 1 || a[i].x != a[i - 1].x) tt = 0;
lh = a[i].y;//lh表示当前树木的行坐标
if(++h[lh] >= k && ycnt[lh] - h[lh] >= k){//左右两边都符合
lv = c[h[lh]][k] * c[ycnt[lh] - h[lh]][k];//我们存到树状数组的东西
}else{
lv = 0;
}
ins(lh, lv - r[lh]);//如果不符合,就减去之前符合的,变成0
r[lh] = lv;
tt ++;//别忘了
if(i == w || a[i].x != a[i + 1].x || a[i + 1].y - a[i].y <= 1 || tt <k || xcnt[a[i].x] - tt < k)//上下都符合
continue;
ans += c[tt][k] * c[xcnt[a[i].x] - tt][k] * (ask(a[i + 1].y - 1) - ask(a[i].y));
}//这里上面空地正好是a[i + 1].y - 1,下面是a[i].y + 1,由于树状数组的操作,所以这样写
printf("%d", ans & 2147483647);//自然溢出
return 0;
}
标签:坐标 宏定义 cst 题目 多少 表示 int 个数 离散
原文地址:https://www.cnblogs.com/LMSH7/p/9552477.html