您的位置:首页 > 其它

[HNOI2008]Cards

2017-10-22 14:51 141 查看

题目描述

小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.

进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绿色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.

Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).

输入输出格式

输入格式:

第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1<p<100)。n=Sr+Sb+Sg。接下来 m 行,每行描述一种洗牌法,每行有 n 个用空格隔开的整数 X1X2...Xn,恰为 1 到 n 的一个排列,表示使用这种洗牌法,第 i位变为原来的 Xi位的牌。输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种

洗牌法,都存在一种洗牌法使得能回到原状态。

100%数据满足 Max{Sr,Sb,Sg}<=20。

输出格式:

不同染法除以P的余数

输入输出样例

输入样例#1: 复制

1 1 1 2 7
2 3 1
3 1 2


输出样例#1: 复制

2


说明

有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。

[b]题目大意:给出n张牌,分别染a张红色,b张蓝色,c张绿色(n=a+b+c),给出m个置换,问不同的染色方案。[/b]

[b]红色部分就是告述你这些置换构成置换群[/b]

[b]置换群中的染色方案问题可用polya定理解决。[/b]

[b]只要满足同一循环染同一种色[/b]

[b]因为3种颜色要满足数量限制,不能用polya,但可以用burnside[/b]

[b]所以用三维背包求出在置换$a_j$下不变的元素个数$D(a_j)$[/b]

[b]还要算上不置换,也就是单位置换[/b]

[b]所以总共有$|G|=m+1$种置换,根据burnside引理[/b]

[b]$ans=\frac{1}{G}\sum_{j=1}^{m+1}D(a_j)$[/b]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int sr,sb,sg,n,m,p,inv;
int vis[1001],f[101][21][21][21],tot,A[1001],s[1001],ans;
int qpow(int x,int y)
{
int res=1;
while (y)
{
if (y&1) res=res*x%p;
x=x*x%p;
y/=2;
}
return res;
}
int dfs(int x,int cnt)
{
if (vis[x])
return cnt;
vis[x]=1;
return dfs(A[x],cnt+1);
}
int main()
{int i,a,b,c;
cin>>sr>>sb>>sg>>m>>p;
n=sr+sb+sg;
inv=qpow(m+1,p-2);
while (m--)
{
tot=0;
memset(vis,0,sizeof(vis));
for (i=1;i<=n;i++)
scanf("%d",&A[i]);
for (i=1;i<=n;i++)
if (vis[i]==0)
{
s[++tot]=dfs(i,0);
}
memset(f,0,sizeof(f));
f[0][0][0][0]=1;
for (i=1;i<=tot;i++)
{
for (a=0;a<=sr;a++)
{
for (b=0;b<=sb;b++)
{
for (c=0;c<=sg;c++)
{
if (a>=s[i])
{
f[i][a][b][c]+=f[i-1][a-s[i]][b][c];
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
if (b>=s[i])
{
f[i][a][b][c]+=f[i-1][a][b-s[i]][c],f[i][a][b][c]%=p;
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
if (c>=s[i])
{
f[i][a][b][c]+=f[i-1][a][b][c-s[i]];
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
}
}
}
}
ans+=f[tot][sr][sb][sg];
if (ans>=p) ans-=p;
}
memset(f,0,sizeof(f));f[0][0][0][0]=1;
for (i=1;i<=n;i++)
{
for (a=0;a<=sr;a++)
{
for (b=0;b<=sb;b++)
{
for (c=0;c<=sg;c++)
{
if (a>=1)
{
f[i][a][b][c]+=f[i-1][a-1][b][c];
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
if (b>=1)
{
f[i][a][b][c]+=f[i-1][a][b-1][c],f[i][a][b][c]%=p;
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
if (c>=1)
{
f[i][a][b][c]+=f[i-1][a][b][c-1];
if (f[i][a][b][c]>=p) f[i][a][b][c]-=p;
}
}
}
}
}
ans+=f
[sr][sb][sg];
if (ans>=p) ans-=p;
cout<<ans*inv%p;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: