bzoj1004 HNOI2008 Cards

题目描述

题解:

求轨道数。

$Burnside$引理:轨道数=各置换方法下不动点个数的平均值。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,sr,sb,sg,m,p;
int x[70][70],ans;
ll fastpow(ll x,int y)
{
    ll ret = 1;
    while(y)
    {
        if(y&1)ret=ret*x%p;
        x=x*x%p;
        y>>=1;
    }
    return ret;
}
int inv(int x)
{
    return fastpow(x,p-2);
}
bool vis[70];
int sta[70],tl;
int dp[25][25][25];
int cal(int a[70])
{
    memset(vis,0,sizeof(vis));
    tl = 0;
    for(int i=1;i<=n;i++)if(!vis[i])
    {
        int u = i;
        int cnt = 0;
        while(!vis[u])
        {
            cnt++;
            vis[u] = 1;
            u = a[u];
        }
        sta[++tl] = cnt;
    }
    memset(dp,0,sizeof(dp));
    dp[0][0][0] = 1;
    for(int i=1;i<=tl;i++)
        for(int j=sr;j>=0;j--)
            for(int k=sb;k>=0;k--)
                for(int l=sg;l>=0;l--)
                    if(dp[j][k][l])
                    {
                        if(j+sta[i]<=sr)(dp[j+sta[i]][k][l]+=dp[j][k][l])%=p;
                        if(k+sta[i]<=sb)(dp[j][k+sta[i]][l]+=dp[j][k][l])%=p;
                        if(l+sta[i]<=sg)(dp[j][k][l+sta[i]]+=dp[j][k][l])%=p;
                    }
    return dp[sr][sb][sg];
}
int main()
{
    scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p);
    n = sr+sg+sb;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&x[i][j]);
    for(int i=1;i<=n;i++)
        x[0][i]=i;
    int ans = 0;
    for(int i=0;i<=m;i++)
        ans=(ans+cal(x[i]))%p;
    ans = (ans*inv(m+1))%p;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-02-22 16:30  LiGuanlin  阅读(112)  评论(0编辑  收藏  举报