BZOJ1004: [HNOI2008]Cards
三维01背包算出在每一个置换下不变的染色方案数,Burnside引理计算答案。
PS:数据太水所以只算恒等置换也是可以过的。
#include<bits/stdc++.h> using namespace std; int n,m,p,x,y,z; bool u[61]; int f[21][21][21],s[61],v[61]; int power(int u,int v){ int d=1; for(;v;v>>=1){ if(v&1) d=d*u%p; u=u*u%p; } return d; } void add(int& u,int v){ u=(u+v)%p; } int main(){ scanf("%d%d%d%d%d",&x,&y,&z,&m,&p); n=x+y+z; int ans=1; for(int i=1;i<=n;++i) ans=ans*i%p; for(int i=1;i<=x;++i) ans=ans*power(i,p-2)%p; for(int i=1;i<=y;++i) ans=ans*power(i,p-2)%p; for(int i=1;i<=z;++i) ans=ans*power(i,p-2)%p; for(int t=0;t!=m;++t){ for(int i=1;i<=n;++i) scanf("%d",s+i); memset(u,0,sizeof u); int cnt=0; for(int i=1;i<=n;++i) if(!u[i]){ int k=u[i]=1; for(int j=s[i];j!=i;j=s[j]) k+=u[j]=1; v[cnt++]=k; } memset(f,0,sizeof f); f[0][0][0]=1; for(int a=0;a!=cnt;++a) for(int i=x;~i;--i) for(int j=y;~j;--j) for(int k=z;~k;--k){ if(i>=v[a]) add(f[i][j][k],f[i-v[a]][j][k]); if(j>=v[a]) add(f[i][j][k],f[i][j-v[a]][k]); if(k>=v[a]) add(f[i][j][k],f[i][j][k-v[a]]); } add(ans,f[x][y][z]); } printf("%d\n",ans*power(m+1,p-2)%p); }