这道题反映出我群论不是很熟练,理解上有些问题
直接burnside引理,对于一种置换下相同的方案数用DP或记忆化搜索求,然后乘个逆元
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 22;
const int maxm = 62;
int Mod;
int n,m;
int a[maxm],n1,n2,n3;
int pw(int x,int k)
{
int r=1,tt=x;
for(;k;k>>=1,tt=tt*tt%Mod) if(k&1) r=r*tt%Mod;
return r;
}
int f[2][maxm][maxm][maxm];
int N(int x) { return pw(x,Mod-2); }
int cir[maxm],cnt;
int tp;
bool v[maxm];
void find_(int x)
{
if(v[x]) { cir[++cnt]=tp; return ; }
tp++; v[x]=true; find_(a[x]);
}
int main()
{
scanf("%d%d%d%d%d",&n1,&n2,&n3,&m,&Mod);
n=n1+n2+n3;
int re=0;
for(int i=1;i<=m+1;i++)
{
if(i!=m+1)
{
for(int j=1;j<=n;j++) scanf("%d",&a[j]);
cnt = 0;
memset(v,false,sizeof v);
for(int i=1;i<=n;i++)
if(!v[i]) find_(i);
}
else
{
for(int j=1;j<=n;j++) cir[j]=1;
cnt=n;
}
int now=1;
memset(f[now],0,sizeof f[now]);
f[now][n1][n2][n3]=1;
for(int j=1;j<=cnt;j++)
{
now=1^now; memset(f[now],0,sizeof f[now]);
for(int x=n1;x>=0;x--)
{
for(int y=n2;y>=0;y--) for(int l=n3;l>=0;l--)
{
f[1^now][x][y][l]%=Mod;
if(f[1^now][x][y][l])
{
int k=f[1^now][x][y][l];
if(x>=cir[j]) f[now][x-cir[j]][y][l]+=k;
if(y>=cir[j]) f[now][x][y-cir[j]][l]+=k;
if(l>=cir[j]) f[now][x][y][l-cir[j]]+=k;
}
}
}
}
re+=f[now][0][0][0];
}
re%=Mod;
re=re*N(m+1)%Mod;
printf("%d\n",re);
return 0;
}