【bzoj1004】Cards 置换群+动态规划+乘法逆元

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1004

【题解】

染色法就相当于置换,要求的洗牌法就相当于等价类的个数。

那么根据burnside定理,ans就是每种置换下不动点的数目的和除以m

在不动点的限定下,所有循环节的颜色一定相同

然而这道题关于颜色有限制,那么我们可以用f[i][j][k]表示用了i种颜色1,j种颜色2,k种颜色3的相同的方案数,b[h]表示循环节的长度,那么可以得到f[i][j][k]=f[i-d[h]][j][k]+f[i][j-d[h]][k]+f[i][j][k-d[h]]

求出ans之后,由于计算出的ans是取模后的结果,然后要除以m,然后。。。乘法逆元解决。

最后别忘了,除了题上给出的置换外,还有一个固定的置换,就是自身的置换。

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int sr,sb,sg,m,n,mod,ans,a[61][61],b[61],f[61][61][61],d[61];
inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int dp(int x)
{
    for(int i=1;i<=n;i++)  b[i]=0;
    int sum=0,p=0;
    for(int i=1;i<=n;i++)
        if(!b[i])
        {
            p=i;  b[p]=1;  d[++sum]=1;
            while(!b[a[x][p]])
            {
                b[a[x][p]]=1;
                d[sum]++;
                p=a[x][p];
            }
        }
    for(int i=sr;i>=0;i--)
        for(int j=sb;j>=0;j--)
            for(int k=sg;k>=0;k--)
                f[i][j][k]=0;
    f[0][0][0]=1;
    for(int h=1;h<=sum;h++)
        for(int i=sr;i>=0;i--)
            for(int j=sb;j>=0;j--)
                for(int k=sg;k>=0;k--)
                {
                    if(i>=d[h])  f[i][j][k]=(f[i][j][k]+f[i-d[h]][j][k])%mod;
                    if(j>=d[h])  f[i][j][k]=(f[i][j][k]+f[i][j-d[h]][k])%mod;
                    if(k>=d[h])  f[i][j][k]=(f[i][j][k]+f[i][j][k-d[h]])%mod;
                }
    return f[sr][sb][sg];
}
void exgcd(int a,int b,int &x,int &y)
{
    if(b==0)  {x=1;  y=0;  return;}
    exgcd(b,a%b,x,y);
    int t=x;  x=y;  y=t-a/b*y;
}
int main()
{
    sr=read();  sb=read();  sg=read();  m=read();  mod=read();
    n=sr+sb+sg;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            a[i][j]=read();
    m++;
    for(int i=1;i<=n;i++)  a[m][i]=i;
    for(int i=1;i<=m;i++)  ans=(ans+dp(i))%mod;
    int x,y;
    exgcd(m,mod,x,y);
    while(x<0)  x+=mod;
    printf("%d\n",ans*x%mod);
    return 0;
}


你可能感兴趣的:(bzoj,乘法逆元,普通dp,置换群)