• [BZOJ1004] [HNOI2008]Cards解题报告(Burnside引理)


    Description

      小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).  

        这道题做了挺久的...感觉还是对于Burnside引理理解的不够透彻吧。

        Burnside引理:

          L=1/|G|*(c1+c2+...ck),ci表示第i种置换的不动置换类。如置换:(123)(45)(6)中的不动置换类只有(6)一个。

        这道题不能用Polya定理,因为每种颜色有具体的数量要求,不能任意染色。

        题目中给的洗牌方法,很显然就是一个个置换了。那么不动置换类要怎么求呢?

        颜色相同的看上去也一样,所以如果置换后位置上的颜色与原位置的颜色相同,也算是不动置换类

        而这道题需要思考的是,我们应该怎样把染色方案带到公式里去。

        答案是,将一个染色方案看做一个元素。

        即这道题中的不动置换类为经过该种置换后仍然不变的一个染色方案。

        那么不动置换类的个数即ci也就是满足在经过i种置换后每一位上颜色都不变的染色方案总数。

        则每个循环中要染同一种颜色,可以用01背包来计算方案数。

        最后不能忘记最重要也是最基础的一个置换即(1)(2)(3)...(n)这个置换。

        实现的过程中需要用到求乘法逆元。稍加注意即可。

         

    program bzoj1004;
    const maxn=65;
    var i,j,t1,t2,t3:longint;
        s1,s2,s3,m,p,n,ans,tot,sum,x:int64;
        f:array[-1..maxn,-1..maxn,-1..maxn]of int64;
        vis:array[-1..maxn]of boolean;
        a:array[-1..maxn]of longint;
    
    function ex_Euclid(a,b:int64;var x,y:int64):int64;
    var t:int64;
    begin
        if b=0 then
        begin
            x:=1;y:=0;exit(a);
        end else
        begin
            ex_Euclid:=ex_Euclid(b,a mod b,x,y);
            t:=x;x:=y;y:=t-(a div b)*y;
        end;
    end;
    
    function inverse(a:int64):int64;
    var x,y,tem,d:int64;
    begin
        d:=ex_Euclid(a,p,x,y);
        if d<>1 then exit(-1) else
        begin
            if x<0 then
            begin
                tem:=(-x) div p;
                x:=x+tem*p;y:=y-tem*a;
            end;
            if x<0 then
            begin
                x:=x+p;y:=y-p;
            end;
        end;
        exit(x);
    end;
    
    begin
        readln(s1,s2,s3,m,p);n:=s1+s2+s3;
        ans:=1;
        for i:=2 to n do ans:=(ans*i) mod p;
        for i:=2 to s1 do ans:=(ans*inverse(i)) mod p;
        for i:=2 to s2 do ans:=(ans*inverse(i)) mod p;
        for i:=2 to s3 do ans:=(ans*inverse(i)) mod p;
            for i:=1 to m do
        begin
            fillchar(f,sizeof(f),0);
            fillchar(vis,sizeof(vis),true);
            f[0,0,0]:=1;sum:=0;
            for j:=1 to n do read(a[j]);readln;
            for j:=1 to n do if vis[j] then
            begin
                tot:=0;
                x:=a[j];vis[j]:=false;
                while x<>j do
                begin
                    inc(tot);
                    vis[x]:=false;
                    x:=a[x];
                end;
                inc(sum,tot);
                for t1:=0 to sum do
                    for t2:=0 to sum-t1 do
                    begin
                        t3:=sum-t1-t2;
                        if t1-tot>=0 then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1-tot,t2,t3]) mod p;
                        if t2-tot>=0 then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1,t2-tot,t3]) mod p;
                        if t3-tot>=0 then f[t1,t2,t3]:=(f[t1,t2,t3]+f[t1,t2,t3-tot]) mod p;
                    end;
            end;
        end;
        ans:=(ans*inverse(m+1)) mod p;
        writeln(ans);
    end.

     

          

  • 相关阅读:
    eclipse配置spring4.0环境详细教程
    PostgreSQL精简命令:
    Unity3D项目之 Survival Shooter 记录
    Unity UGUI 实现简单拖拽功能
    Unity UGUI实现Button按钮长按状态的判断
    Unity获取文件夹下指定类型的文件数量
    Unity5 AssetBundle打包加载及服务器加载
    Unity5.X 新版AssetBundle打包控制
    Unity基于DFGUI的TreeView设计
    Unity5.X 新版AssetBundle使用方案及策略
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4402207.html
Copyright © 2020-2023  润新知