1. 程式人生 > >bzoj 1004: [HNOI2008]Cards

bzoj 1004: [HNOI2008]Cards

/**************************************************************
    Problem: 1004
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:264 ms
    Memory:1896 kb
***************************************************************
*/   /*     剛好在學polya 就送來一個例題。。。     首先 那b啥定理的優化版polya不起作用     因為規定了某一種顏色的數量     所以使用dp揹包計數      f(r,b,g) 表示 用r個紅 b個藍 g個綠 的方案數     (我們用不了優化 只能把所有方案數算出來。。)     注意 單位元(也就是不置換)也算一種置換 要算進去     還有 揹包技術和01揹包類似。 是倒著for 不然就要記錄重複。。。
*/ #include<cstdio> #include<cstring> using namespace std; const int N=65; int sr,sb,sg,n,m,p,cnt,ans; int a[N],size[N],f[N][N][N]; bool vis[N]; int ksm(int a,int b,int p) {     int res=1;for(;b;b>>=1)     {         
if(b&1) (res*=a)%=p; (a*=a)%=p;     } return res; } int getans() {     memset(vis,0,sizeof(vis));     memset(f,0,sizeof(f));     memset(size,0,sizeof(size));     f[0][0][0]=1;cnt=0;     for(int i=1;i<=n;i++) if(!vis[i])     {         cnt++;  int x=i;         while(!vis[x]) {size[cnt]++;vis[x]=1;x=a[x];}     }     for(int i=1;i<=cnt;i++)     for(int r=sr;r>=0;r--)     for(int b=sb;b>=0;b--)     for(int g=sg;g>=0;g--)     {         if(r>=size[i]) (f[r][b][g]+=f[r-size[i]][b][g])%=p;         if(b>=size[i]) (f[r][b][g]+=f[r][b-size[i]][g])%=p;         if(g>=size[i]) (f[r][b][g]+=f[r][b][g-size[i]])%=p;     }     return f[sr][sb][sg]; } int main() {     scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p);     n=sr+sb+sg;     for(int k=1;k<=m;k++)     {         for(int i=1;i<=n;i++) scanf("%d",&a[i]);         (ans+=getans())%=p;   // 計算每組置換的貢獻     }     for(int i=1;i<=n;i++) a[i]=i;     (ans+=getans())%=p;     // 單位元的計算      (ans*=ksm(m+1,p-2,p))%=p;     printf("%d\n",ans%p);     return 0; }