题目:BZOJ1004.
题目大意:给定基于
n
n
n个元素的
m
m
m个置换组成置换群(未包含单位置换),要求给这
n
n
n个元素染三种颜色使得第一种颜色数量为
s
r
sr
sr,第二种颜色数量为
s
b
sb
sb,第三种颜色数量为
s
g
sg
sg,求本质不同的染色方案数对
p
p
p取模.
1
≤
s
r
,
s
b
,
s
g
≤
20
,
1
≤
m
≤
60
,
n
=
s
r
+
s
b
+
s
g
,
m
+
1
<
p
<
100
1\leq sr,sb,sg\leq 20,1\leq m\leq 60,n=sr+sb+sg,m+1<p<100
1≤sr,sb,sg≤20,1≤m≤60,n=sr+sb+sg,m+1<p<100.
这道题有了颜色数量的限制,不能直接使用Polya定理了.
考虑Polya定理的证明过程,我们也构造以染色方案作为元素构成的集合 S S S,并构造基于 S S S的置换群 G G G.
此时我们发现只需要把染色方案中不满足颜色数量的踢出 S S S就可以进行推导了.
为了套Burnside引理,我们需要计算经过某个置换 A A A后不变的方案数,与Polya定理类似的,这个方案数也需要满足每一个轮换内部染色相同的条件.
此时我们可以把每一个轮换看成一个重量为它的长度的物品,现在把这些物品染色,需要满足染某个颜色的物品重量之和为对应的数量限制,用DP求出方案数即可套用Burnside引理.
时间复杂度 O ( n 4 m ) O(n^4m) O(n4m).
注意初始时没有单位置换,需要加入一个单位置换,并且最后的 1 ∣ G ∣ \frac{1}{|G|} ∣G∣1中 ∣ G ∣ = m + 1 |G|=m+1 ∣G∣=m+1.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=60,M=20;
int mod;
int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
int sub(int a,int b){return a-b<0?a-b+mod:a-b;}
int mul(int a,int b){return (LL)a*b%mod;}
void sadd(int &a,int b){a=add(a,b);}
void ssub(int &a,int b){a=sub(a,b);}
void smul(int &a,int b){a=mul(a,b);}
int Power(int a,int k){
int res=1;
for (;k;k>>=1,smul(a,a))
if (k&1) smul(res,a);
return res;
}
int n,m,sr,sb,sg;
int p[N+9],vis[N+9];
int a[N+9],ca;
void Get_a(){
for (int i=1;i<=n;++i) vis[i]=0;
ca=0;
for (int i=1;i<=n;++i)
if (!vis[i]){
a[++ca]=1;vis[i]=1;
for (int j=p[i];j^i;j=p[j]) ++a[ca],vis[j]=1;
}
}
int dp[M+9][M+9][M+9];
void Get_dp(){
for (int i=0;i<=sr;++i)
for (int j=0;j<=sb;++j)
for (int k=0;k<=sg;++k) dp[i][j][k]=0;
dp[0][0][0]=1;
for (int i=1;i<=ca;++i)
for (int j=sr;j>=0;--j)
for (int k=sb;k>=0;--k)
for (int t=sg;t>=0;--t){
if (j>=a[i]) sadd(dp[j][k][t],dp[j-a[i]][k][t]);
if (k>=a[i]) sadd(dp[j][k][t],dp[j][k-a[i]][t]);
if (t>=a[i]) sadd(dp[j][k][t],dp[j][k][t-a[i]]);
}
}
int ans;
Abigail into(){
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",&p[j]);
Get_a();
Get_dp();
sadd(ans,dp[sr][sb][sg]);
}
}
Abigail work(){
for (int i=1;i<=n;++i) p[i]=i;
Get_a();
Get_dp();
sadd(ans,dp[sr][sb][sg]);
}
Abigail outo(){
printf("%d\n",mul(ans,Power(m+1,mod-2)));
}
int main(){
into();
work();
outo();
return 0;
}