bzoj4487: [Jsoi2015]染色问题
隔壁Rose爷爷:这个随便容斥一下写完就过了
我:。。。
我的做法很菜鸡,首先颜色给它变成最多用多少,然后再容斥
然后搞二维你设f[i][j]为i行为0j列为0的数量,再考虑容斥会发现一个很像二维二项式反演的东西。。。
我不知道能不能直接用啊(捂脸,那就设了个类似前缀和带上组合数的东西,先反演出这个,再反演出f
其实三个容斥可以套在一起直接算。。。。
成功卡常。。
有个更强的推导 这个二项式定理还是用得很妙的 我的博客没法看了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int maxn=4e2+10; const LL mod=1e9+7; LL C[maxn][maxn]; void yu() { C[0][0]=1; for(int i=1;i<maxn;i++) { C[i][0]=1; for(int j=1;j<=i;j++) { C[i][j]=C[i-1][j]+C[i-1][j-1]; if(C[i][j]>=mod)C[i][j]-=mod; } } } LL g[maxn][maxn],h[maxn],mi[maxn*maxn]; int main() { int n,m,cc; scanf("%d%d%d",&n,&m,&cc); yu(); int cop=1;LL ans=0; for(int c=cc;c>=0;c--) { mi[0]=1;for(int i=1;i<=n*m;i++)mi[i]=mi[i-1]*(c+1)%mod; for(int i=0;i<n;i++) for(int j=0;j<m;j++) g[i][j]=C[n][i]*C[m][j]%mod*mi[(n-i)*(m-j)]%mod; for(int i=0;i<=n;i++)g[i][m]=C[n][i]; for(int j=0;j<=m;j++)g[n][j]=C[m][j]; for(int j=0;j<=m;j++) { int op=1; h[j]=0; for(int u=0;u<=n;u++) { if(op==1)h[j]+=g[u][j]; else h[j]-=g[u][j]; op=-op; } h[j]%=mod; if(h[j]<0)h[j]+=mod; } LL f=0; int op=1; for(int v=0;v<=m;v++) { if(op==1)f+=h[v]; else f-=h[v]; op=-op; } f%=mod; if(f<0)f+=mod; if(cop==1)ans+=C[cc][c]*f%mod; else ans-=C[cc][c]*f%mod; cop=-cop; } ans%=mod; if(ans<0)ans+=mod; printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.