bzoj 1004 burnside 引理+DP

  对于burnside引理需要枚举染色,这道题属于burnside的一种简单求解的方法,就是polya,我们可以使每一种置换中的循环节中的元素的颜色都相同,那么这样的话就可以直接DP了,我们可以将m个置换单独考虑,处理出当前置换中各个循环节,那么用w[aa][bb][cc]表示在使用了aa个颜色1,bb个颜色2,cc个颜色3时,我们的轨道数,那么我们可以通过背包来累加答案,w[aa][bb][cc]+=w[aa-b[i]][bb][cc] w[aa][bb][cc]+=w[aa][bb-b[i]][cc] w[aa][bb][cc]+=w[aa-b[i]][bb][cc-b[i]]。

  

/**************************************************************

    Problem: 1004

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:84 ms

    Memory:868 kb

****************************************************************/

 

//By BLADEVIL

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 70

 

using namespace std;

 

int sa,sb,sc,m,n,p,ans;

int a[maxn],b[maxn],w[25][25][25],flag[maxn];

 

int mi(int a,int k) { 

    int ans=1;

    while (k) {

        if (k&1) ans=(ans*a)%p;

        a=(a*a)%p;

        k>>=1;

    }

    return ans;

}

 

int main() {

    scanf("%d%d%d%d%d",&sa,&sb,&sc,&m,&p); n=sa+sb+sc;

    ans=1;

    for (int i=1;i<=n;i++) ans=(ans*i)%p;

    //printf("%d\n",ans);

    //printf("|%d\n",mi(3,3));

    for (int i=1;i<=sa;i++) ans=(ans*mi(i,p-2))%p;

    for (int i=1;i<=sb;i++) ans=(ans*mi(i,p-2))%p;

    for (int i=1;i<=sc;i++) ans=(ans*mi(i,p-2))%p;

    //printf("%d\n",ans);

    int cur=m;

    while (cur--) {

        for (int i=1;i<=n;i++) scanf("%d",&a[i]);

        memset(flag,0,sizeof flag);

        memset(b,0,sizeof b);

        memset(w,0,sizeof w);

        for (int i=1;i<=n;i++) if (!flag[i]) {

            b[++b[0]]=1; flag[i]=1;

            for (int cur=a[i];cur!=i;cur=a[cur]) b[b[0]]++,flag[cur]=1;

        }

        //for (int i=1;i<=b[0];i++) printf("%d ",b[i]); printf("\n");

        w[0][0][0]=1;

        for (int i=1;i<=b[0];i++)

            for (int aa=sa;aa;aa--)

                for (int bb=sb;bb;bb--)

                    for (int cc=sc;cc;cc--) {

                        if (aa>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa-b[i]][bb][cc])%p;

                        if (bb>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa][bb-b[i]][cc])%p;

                        if (cc>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa][bb][cc-b[i]])%p;

                    }

        ans=(ans+w[sa][sb][sc])%p;

        //printf("%d\n",ans);   

    }

    ans=(ans*mi(m+1,p-2))%p;

    printf("%d\n",ans);

    return 0;

}

 

你可能感兴趣的:(ide)