码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ】1003 Cards

时间:2015-07-22 22:48:48      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:bzoj   burnside引理   polya计数   hnoi   

【解析】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; //Basic
int map[N][N],d[N],v[N],cnt;    //Substitution
int f[N][N][N]; //Damatic Programming
int 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>


版权声明:本文为博主原创文章,未经博主允许不得转载。

【BZOJ】1003 Cards

标签:bzoj   burnside引理   polya计数   hnoi   

原文地址:http://blog.csdn.net/u013598409/article/details/47010555

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!