首先,加入一个置换,每个数i对应自身
计算方案数%P
ans=∑D(i)/M (1<=i<=M)
D(i)表示在置换i下不变的染色数
考虑如何求D(i)
对于置换i,求出它的循环节,每个循环节必须染成同一个颜色,但是对总数有限制
f[i][j][k]表示用i个红色,j个蓝色,k个绿色的方案数
把每个循环节视为一个物品,权值为长度。
f[i][j][k]=f[i-d[p]][j][k]+f[i][j-d[p]][k]+f[i][j][k-d[p]]
d[p]表示第p个循环节的长度
计算方案数%P
ans=∑D(i)/M (1<=i<=M)
D(i)表示在置换i下不变的染色数
考虑如何求D(i)
对于置换i,求出它的循环节,每个循环节必须染成同一个颜色,但是对总数有限制
f[i][j][k]表示用i个红色,j个蓝色,k个绿色的方案数
把每个循环节视为一个物品,权值为长度。
f[i][j][k]=f[i-d[p]][j][k]+f[i][j-d[p]][k]+f[i][j][k-d[p]]
d[p]表示第p个循环节的长度
注意枚举顺序,p要在最外面,保证每个物品只取一次
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
int f[50][50][50];
int a[100],b[100];
bool vis[100];
int n,m,ans,mod,sr,sb,sg;
int power(int x,int y)
{
int ans=1;
while (y)
{
if (y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
int solve()
{
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
int tot=0;
for (int i=1;i<=n;i++)
if (!vis[i])
{
tot++;b[tot]=1;vis[i]=1;
int j=i;
while (!vis[a[j]]) j=a[j],vis[j]=1,b[tot]++;
}
f[0][0][0]=1;
for (int p=1;p<=tot;p++)
for (int i=sr;i>=0;i--)
for (int j=sb;j>=0;j--)
for (int k=sg;k>=0;k--)
{
if (i>=b[p]) f[i][j][k]+=f[i-b[p]][j][k];
if (j>=b[p]) f[i][j][k]+=f[i][j-b[p]][k];
if (k>=b[p]) f[i][j][k]+=f[i][j][k-b[p]];
f[i][j][k]%=mod;
}
return f[sr][sb][sg];
}
int main()
{
scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&mod);
n=sr+sb+sg;
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++) scanf("%d",&a[j]);
ans+=solve();ans%=mod;
}
m++;
for (int i=1;i<=n;i++) a[i]=i;
ans+=solve();ans%=mod;
ans=ans*power(m,mod-2)%mod;
printf("%d\n",ans);
return 0;
}