【BZOJ1004】Cards(HNOI2008)-Burnside引理+DP+逆元
测试地址:Cards
做法:本题需要用到Burnside引理+DP+逆元。
注意到,按照题目中给的定义,给出的
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a,b,c,m,p,n,x[110];
int f[65][25][25][25],g[65],ans=0;
bool vis[65];
int power(int a,int b)
{
int s=1,ss=a;
while(b)
{
if (b&1) s=(s*ss)%p;
b>>=1;ss=(ss*ss)%p;
}
return s;
}
void work()
{
int tot=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if (!vis[i])
{
g[++tot]=0;
int now=i;
while(!vis[now]) vis[now]=1,g[tot]++,now=x[now];
}
memset(f,0,sizeof(f));
f[0][0][0][0]=1;
for(int i=1;i<=tot;i++)
{
for(int sa=0;sa<=a;sa++)
for(int sb=0;sb<=b;sb++)
for(int sc=0;sc<=c;sc++)
{
if (sa>=g[i]) f[i][sa][sb][sc]=(f[i][sa][sb][sc]+f[i-1][sa-g[i]][sb][sc])%p;
if (sb>=g[i]) f[i][sa][sb][sc]=(f[i][sa][sb][sc]+f[i-1][sa][sb-g[i]][sc])%p;
if (sc>=g[i]) f[i][sa][sb][sc]=(f[i][sa][sb][sc]+f[i-1][sa][sb][sc-g[i]])%p;
}
}
ans=(ans+f[tot][a][b][c])%p;
}
int main()
{
scanf("%d%d%d%d%d",&a,&b,&c,&m,&p);
n=a+b+c;
for(int i=1;i<=n;i++) x[i]=i;
work();
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++) scanf("%d",&x[j]);
work();
}
ans=(power(m+1,p-2)*ans)%p;
printf("%d",ans);
return 0;
}