luogu 2154 离散化+杨辉三角+树状数组
将纵向固定,每次在横向找两个点,计算其中间墓地的贡献答案,离散化后同一行的预处理个数,
树状数组内存储C[up[i]][k] * C[down[i][k] 的值,每次更新时 down[横坐标]++;
c[up[i]][k]*C[down[i]][k] - C[up[i]+1][k]*C[down[i]-1][k] 加入这个值即可
左右答案利用 lf(左侧点数)计算
详见代码
#include<bits/stdc++.h> #define int long long #define rep(i,x,y) for(register int i=x;i<=y;i++) #define dec(i,x,y) for(register int i=x;i>=y;i--) #define mod 2147483648LL using namespace std; const int W=100050; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;}int n,m,w,k,h[2*W],allheng[2*W],allshu[2*W],down[2*W],c[2*W],C[W][15],ans; inline void change(int x,int d){for(int i=x;i<=2*w;i+=i&(-i)) c[i]=(c[i]+d)%mod;return;} inline int query(int x){int res=0;for(int i=x;i;i-=i&(-i)) res=(res+c[i])%mod;return res;} struct node{int x,y;}a[W];bool cmp(node a,node b){if(a.y==b.y)return a.x<b.x;return a.y<b.y;} inline void getc(){C[0][0]=1; rep(i,1,w){C[i][0]=1; rep(j,1,min(i,k)) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;}} inline int find(int x){ int l=1,r=2*w;while(l<=r){ int mid=(l+r)>>1; if(h[mid]<x) l=mid+1;else if(x<h[mid]) r=mid-1;else return mid;}} #undef int int main(){ #define int long long //预处理和读入 n=read(),m=read(),w=read(); rep(i,1,w) a[i].x=read(),a[i].y=read(),h[2*i-1]=a[i].x,h[2*i]=a[i].y; k=read(); getc(); sort(h+1,h+1+2*w); sort(a+1,a+1+w,cmp); rep(i,1,w) allshu[find(a[i].x)]++,allheng[find(a[i].y)]++; int lf; rep(i,1,w){ if(1<i&&a[i-1].y==a[i].y){ lf++;//左侧的点数 int t1=query(find(a[i].x)-1)-query(find(a[i-1].x));//纵向 区间内答案之和 int t2=C[lf][k]*C[allheng[find(a[i].y)]-lf][k];//横向 ans=(ans+t1*t2)%mod;} else lf=0; int ii=find(a[i].x);down[ii]++; //已经以乘积的形式放入树状数组 change(ii,(C[down[ii]][k]*C[allshu[ii]-down[ii]][k]-C[down[ii]-1][k]*C[allshu[ii]-down[ii]+1][k])%mod);} if(ans<0) ans+=mod;printf("%lld\n",ans);return 0;}