1. 程式人生 > >HNOI 2008--Cards( 置換群 & DP )

HNOI 2008--Cards( 置換群 & DP )

while clu http solution h+ pri scan -- printf

對群論沒有任何了解的自覺百度。。。

題目鏈接:

http://www.lydsy.com/JudgeOnline/problem.php?id=1003

Solution

請百度“ 伯恩賽德引理 ”。。。

這是一道置換群的題目。。。雖然還要加上DP。。。

如果明白伯恩賽德引理的話。。直接套公式即可。。。

代碼

#include<cstdio>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
int sr,sb,sg,m,n,mod,ans;
int f[70][70][70],g[70],d[70];
bool c[70];
int DP(){
    for(int i=1;i<=n;i++) c[i]=0;
    int sum=0,q;
    for(int i=1;i<=n;i++)
        if(!c[i]){
            d[++sum]=0;q=i;
            while(!c[g[q]]){
                d[sum]++;
                q=g[q];
                c[q]=1;
            }
        }
    for(int i=0;i<=sr;i++)
        for(int j=0;j<=sb;j++)
            for(int k=0;k<=sg;k++)
                f[i][j][k]=0;
    f[0][0][0]=1;
    for(int h=1;h<=sum;h++)
        for(int i=sr;i>=0;i--)
            for(int j=sb;j>=0;j--)
                for(int k=sg;k>=0;k--){
                    if(i>=d[h]) f[i][j][k]=(f[i][j][k]+f[i-d[h]][j][k])%mod;
                    if(j>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j-d[h]][k])%mod;
                    if(k>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j][k-d[h]])%mod;
                }
    return f[sr][sb][sg];
}
int pow(int a,int b){
    int s=1;
    while(b){
        if(b&1) s=s*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return s;
}
int main(){
    ans=0;
    scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&mod);
    f[0][0][0]=1;
    n=sr+sb+sg;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++)
            scanf("%d",&g[j]);
        ans=(ans+DP())%mod;
    }
    for(int i=1;i<=n;i++) g[i]=i;
    ans=(ans+DP())%mod;
    m++;
    ans=ans*pow(m,mod-2)%mod;
    printf("%d\n",ans);
    return 0;
}

This passage is made by Yukino.

HNOI 2008--Cards( 置換群 & DP )