BZOJ 1004: [HNOI2008]Cards

/*
bzoj 1004: [HNOI2008]Cards
http://www.lydsy.com/JudgeOnline/problem.php?id=1004
burside+dp 
置换群 k背包dp求解不动点 burside定理 求逆元
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int Nmax=105;
const int Mmax=65;
int sr,sb,sg,n,m,mod;
int mods[Mmax][Nmax];
int book[Nmax];
int cnt;
int times[Nmax];
int f[Nmax][Nmax][Nmax];

int get_num(int x)
{
    cnt=0;
    for(int i=1;i<=n;i++)//初始化循环节
    {
        book[i]=0;
        times[i]=0;
    }    
    for(int i=0;i<=sr;i++)//初始化背包
        for(int j=0;j<=sg;j++)
            for(int k=0;k<=sb;k++)
                f[i][j][k]=0;
    for(int i=1;i<=n;i++)//求cnt个循环节的长度
    {
        if(book[i])
            continue;
        int j=i;
        cnt++;
        while(!book[j])
        {
            book[j]=1;
            j=mods[x][j];
            times[cnt]++;
        }
    }
    f[0][0][0]=1;//背包
    for(int i=1;i<=cnt;i++)
        for(int r=sr;r>=0;r--)
        for(int g=sg;g>=0;g--)
        for(int b=sb;b>=0;b--)
        {
            if(r>=times[i])
                f[r][g][b]=(f[r][g][b]+f[r-times[i]][g][b])%mod;
            if(g>=times[i])
                f[r][g][b]=(f[r][g][b]+f[r][g-times[i]][b])%mod;
            if(b>=times[i])
                f[r][g][b]=(f[r][g][b]+f[r][g][b-times[i]])%mod;
        }
    return f[sr][sg][sb];
}

int ex_gcd(int a,int b,int &x,int &y)//solve x,y in a*x+b*y=ex_gcd(a,b,x,y)=gcd(a,b);
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int ans=ex_gcd(b,a%b,x,y);
    int tmp=x;
    x=y;
    y=tmp-a/b*y;
    return ans;
    //x = x0 + (b/gcd)*t
        //y = y0 – (a/gcd)*t
     
}

int get(int a,int m,int c)//get x in a*x=c(mod m)
{
    //we can solve x,y in a*x+b*y=c <=> c%gcd(a,b)==0
    int x,y;
    int gcd=ex_gcd(a,m,x,y);
    if(c%gcd!=0)
        return -1;//error
    x*=c/gcd;
    m=abs(m);
    int ans=x%m;
    while(ans<0)
        ans+=m;
    return ans;
}

int pow(int base,int n)
{
    int ans=1;
    while(n>0)
    {
        if(n&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        n>>=1;
    }
    return ans;
}

int main()
{
    freopen("bzoj1004.in","r",stdin);
    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",&mods[i][j]);
    m++;
    for(int i=1;i<=n;i++)//添加不变置换
        mods[m][i]=i;
    int num=0;
    for(int i=1;i<=m;i++)
        num=(num+get_num(i))%mod;
    // int x=get(m,mod,1);
    int x=pow(m,mod-2);
    // printf("x:%d,mod:%d,num:%d\n",x,mod,num);
    int ans=(num*x)%mod;
    while(ans<0)
        ans-=mod;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-03-08 20:17  BBBob  阅读(165)  评论(0编辑  收藏  举报