【BZOJ】1003 Cards

来源:互联网 发布:中国广电网络投诉电话 编辑:程序博客网 时间:2024/06/04 19:41

【解析】Burnside引理+背包dp+乘法逆元


[Analysis]
这道题卡了好久,就是没想懂置换跟着色是不一样的。

根据burnside引理,在一个置换群作用下不等价类的个数为每个置换作用下不动点个数的平均数。
在这道题中:
置换的对象 —— 每个状态,标号为1—N(这里的N不是题目的N,而是状态的个数)。
不动点 —— 前后染色状态完全相同的状态的个数。
所以就是求经过变换后前后状态完全相同的个数。


[Sum]

Burnside引理几个注意的地方

[1]什么是Burnside引理?
[2]置换的对象是什么?
[3]不动点意味着什么?
[4]着色变换不是置换。


[Code]

<span style="font-size:18px;">/**************************************************************    Problem: 1004    User: y20070316    Language: C++    Result: Accepted    Time:328 ms    Memory:2164 kb****************************************************************/ #include <cstdio>#include <cstring>#include <cstdlib>using namespace std; const int N=70; int Sr,Sb,Sg,n,m,p; //Basicint map[N][N],d[N],v[N],cnt;    //Substitutionint f[N][N][N]; //Damatic Programmingint res;    //Answer inline int read(void){    int s=0,f=1; char c=getchar();    for (;c<'0'||c>'9';c=getchar());    for (;'0'<=c&&c<='9';c=getchar()) s=s*10+c-'0';    return s*f;} void init(void){    Sr=read(),Sb=read(),Sg=read(),n=Sr+Sb+Sg;    m=read(),p=read();    for (int i=1;i<=m;i++)        for (int j=1;j<=n;j++) map[i][j]=read();    m++; for (int j=1;j<=n;j++) map[m][j]=j;} void work(void){    for (int i=1;i<=m;i++)    {        cnt=0; memset(v,0,sizeof v);        memset(d,0,sizeof d);                 for (int j=1;j<=n;j++)            if (!v[j])            {                v[j]=d[++cnt]=1;                for (int k=map[i][j];k^j;k=map[i][k])                     v[k]=1,d[cnt]++;            }                     memset(f,0,sizeof f); f[0][0][0]=1;        for (int i=1;i<=cnt;i++)            for (int j=Sr;j>=0;j--)                for (int k=Sb;k>=0;k--)                    for (int q=Sg;q>=0;q--)                    {                        f[j][k][q]=0;                        if (j>=d[i]) f[j][k][q]=(f[j][k][q]+f[j-d[i]][k][q])%p;                        if (k>=d[i]) f[j][k][q]=(f[j][k][q]+f[j][k-d[i]][q])%p;                        if (q>=d[i]) f[j][k][q]=(f[j][k][q]+f[j][k][q-d[i]])%p;                    }        res=(res+f[Sr][Sb][Sg])%p;    }} int mi(int i,int j){    if (!j) return 1;    int s=mi(i,j>>1);    s=s*s%p;    if (j&1) s=s*i%p;    return s;} void print(void){    int inv=mi(m,p-2);    res=res*inv%p;    printf("%d\n",(res+p)%p);} int main(void){       init();    work();    print();     return 0;}</span>


0 0
原创粉丝点击