bzoj1227: [SDOI2009]虔诚的墓主人(树状数组,组合数)
首先,对于每一块墓地,如果上下左右各有$a,b,c,d$棵树,那么总的虔诚度就是$C_k^a*C_k^b*C_k^c*C_k^d$
那么我们先把所有的点都给离散,然后按$x$为第一关键字,$y$为第二关键字,那么同一横坐标的一定在连续的一段且纵坐标递增
那么对于同一横坐标的两棵常青树,在他们中间的所有空地都有可能满足条件,因为上面的常青树和下面的常青树数量是固定的,所以$C_k^a*C_k^b$的值也是固定的
那么我们就是需要快速求出一段区间里的$C_k^c*C_k^d$,那么我们可以考虑用树状数组来维护。这部分细节可以参考代码
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #define int long long 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 const int N=100005,mod=2147483648; 20 int n,m,k,C[N][15],tt=0,ans,tmp[N],c[N],col,tot[N],cnt[N],r[N],h[N]; 21 struct node{int x,y;}a[N]; 22 inline bool cmp(const node &a,const node &b) 23 {return a.x!=b.x?a.x<b.x:a.y<b.y;} 24 inline bool cmp2(const node &a,const node &b) 25 {return a.y!=b.y?a.y<b.y:a.x<b.x;} 26 inline void add(int x,int y){ 27 for(;x<=col;x+=x&-x) (c[x]+=y)%=mod; 28 } 29 inline int query(int x){ 30 int res=0; 31 for(;x;x-=x&-x) (res+=c[x])%=mod; 32 return res; 33 } 34 signed main(){ 35 //freopen("testdata.in","r",stdin); 36 read();read();n=read(); 37 for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read(); 38 k=read(); 39 for(int i=0;i<=n;++i) C[i][0]=1; 40 for(int i=1;i<=n;++i) 41 for(int j=1;j<=min(i,k);++j) 42 C[i][j]=C[i-1][j]+C[i-1][j-1]; 43 sort(a+1,a+1+n,cmp2); 44 for(int i=1;i<=n;++i) 45 tmp[i]=(i==1||a[i].y!=a[i-1].y)?++tt:tt; 46 for(int i=1;i<=n;++i) cnt[a[i].y=tmp[i]]++;col=a[n].y; 47 sort(a+1,a+1+n,cmp); 48 for(int i=1;i<=n;++i) 49 tmp[i]=(i==1||a[i].x!=a[i-1].x)?++tt:tt; 50 for(int i=1;i<=n;++i) tot[a[i].x=tmp[i]]++; 51 for(int i=1;i<=n;++i){ 52 if(i==1||a[i].x!=a[i-1].x) tt=0; 53 int dy=a[i].y,v=(++h[dy])>=k&&cnt[dy]-h[dy]>=k? 54 1ll*C[h[dy]][k]*C[cnt[dy]-h[dy]][k]%mod:0;++tt; 55 add(dy,v-r[dy]),r[dy]=v; 56 if(i==n||a[i].x!=a[i+1].x||a[i+1].y-a[i].y<=1 57 ||tt<k||tot[a[i].x]-tt<k) continue; 58 (ans+=1ll*C[tt][k]*C[tot[a[i].x]-tt][k]%mod 59 *(query(a[i+1].y-1)-query(a[i].y)))%=mod; 60 } 61 printf("%d\n",(ans>=0?ans:ans+mod)%mod); 62 return 0; 63 }
深深地明白自己的弱小