zoukankan      html  css  js  c++  java
  • [POJ1286&POJ2154&POJ2409]Polya定理

    Polya定理


      L=1/|G|*(m^c(p1)+m^c(p2)+...+m^c(pk))

      G为置换群大小

      m为颜色数量

      c(pi)表示第i个置换的循环节数

      如置换(123)(45)(6)其循环节数为3

    -------------------------------------------------------------------------------------------

     POJ1286&POJ2409

      都是简单的处理串珠子的问题。

      题目中隐藏着3种不同的置换类别。

      1.旋转

        注意不需要顺时针和逆时针分开考虑 因为顺时针旋转k位等同于逆时针旋转(n-k)位。

        另外当旋转了k位时的循环节数为gcd(k,n) 这个略加脑补也可得出。

      2.翻转(对称)

        需要分n的奇偶分开讨论

        当n为奇数时

          只有一种对称,即以每颗珠子与中心的连线所在的直线为对称轴。这个时候循环节数为(n+1)/2。

        当n为偶数时

          有两种对称,一种同奇数时的情况,但是此时相对的两颗珠子所成的直线为同一条

          所以循环节数为n/2+1,情况的数量也要减少一半。

          另一种是以两颗珠子连线的中点与中心连线所在的直线为对称轴。这种情况的循环节数为n/2,情况也是n/2种。

      这两道题的数据范围都很小,所以直接这样处理就可以了。

      

     

    program poj1286;
    var i,n:longint;
        tot,sum:int64;
        w:array[-1..25]of int64;
    
    function gcd(x,y:longint):longint;
    begin
        if y=0 then exit(x) else exit(gcd(y,x mod y));
    end;
    
    begin
        w[0]:=1;
        for i:=1 to 23 do w[i]:=w[i-1]*3;
        readln(n);
        while n<>-1 do
        begin
                    if n=0 then
                    begin
                            writeln(0);
                            readln(n);
                            continue;
                    end;
            tot:=1;sum:=w[n];
            for i:=1 to n-1 do
            begin
                inc(tot);
                inc(sum,w[gcd(i,n)]);
            end;
            if odd(n) then
            begin
                inc(tot,n);
                inc(sum,w[(n+1) >> 1]*n);
            end else
            begin
                inc(tot,n >> 1);
                inc(sum,w[n >> 1+1]*n >> 1);
                inc(tot,n >> 1);
                inc(sum,w[n >> 1]*n >> 1);
            end;
            writeln(sum div tot);
            readln(n);
        end;
    end.
    program poj2409;
    var m,n,tot,sum:int64;
        i:longint;
    
    function w(x:longint):int64;
    var i:longint;
    begin
        w:=1;
        for i:=1 to x do w:=w*m;
    end;
    
    function gcd(x,y:longint):longint;
    begin
            if y=0 then exit(x) else exit(gcd(y,x mod y));
    end;
    
    begin
        readln(m,n);
        while (m<>0)or(n<>0) do
        begin
            tot:=0;sum:=0;
            for i:=1 to n do
            begin
                inc(tot);
                inc(sum,w(gcd(i,n)));
            end;
            if odd(n) then
            begin
                inc(tot,n);
                inc(sum,w((n+1) >> 1)*n);
            end else
            begin
                inc(tot,n >> 1);
                inc(sum,w(n >> 1)* n >> 1);
                inc(tot,n >> 1);
                inc(sum,w(n >> 1+1)* n >> 1);
            end;
            writeln(sum div tot);
            readln(m,n);
        end;
    end.

    ----------------------------------------------------------------------------------

     POJ2154

      

      感觉非常坑啊...

      首先觉得这道题挺好的...数据范围非常大

      由于用到gcd的统计所以自然而然想到了欧拉函数

      然后套一下应该就出来了...

      但是为什么我做了这么久...

      有几个需要注意的地方

      1.最后除以|G|在这里也就是n的步骤由于在取模意义下所以会出错,但是很神奇的发现快速幂的底数也都是n(大概这也是题目中长度和颜色数相同的意图吧),只要将次数-1就可以了。

      2.直接这样会TLE,欧拉函数的求解还需要用欧拉线筛来优化。即用已有的质因子来求phi。过程很简单就不多提了。

      值得一提的是最后一次TLE到AC的跨越仅仅是因为一个变量的类型。即ans变量改成longint就可以过了。

      再一次印证了张老师几年前提到的”空间会影响时间“

      另外在这道题中,正巧将前几天学的欧拉函数和欧拉线筛都运用了起来,感觉非常不错。

    program poj2154;
    const maxn=trunc(sqrt(1000000000));
    var t,test,n,tt:longint;
        vis:array[-1..maxn]of boolean;
        p:array[-1..maxn]of longint;
    
    procedure build;
    var i,j:longint;
    begin
            fillchar(vis,sizeof(vis),true);
            p[0]:=0;
            for i:=2 to maxn do
            begin
                    if vis[i] then
                    begin
                            inc(p[0]);p[p[0]]:=i;
                    end;
                    for j:=1 to p[0] do
                    begin
                            if i*p[j]>maxn then break;
                            vis[i*p[j]]:=false;
                            if i mod p[j]=0 then break;
                    end;
            end;
    end;
    
    function phi(x:longint):longint;
    var i,ans,tem:longint;
    begin
            ans:=x;tem:=x;
        for i:=1 to p[0] do if tem>=p[i]*p[i] then
                    //刚开始写成了tem>=p[i]就失去了优化的意义TAT
        begin
                    if x mod p[i]=0 then ans:=ans div p[i]*(p[i]-1);
                        //在ans是longint的情况下先乘后除会爆
                    while x mod p[i]=0 do x:=x div p[i];
        end else break;
        if x<>1 then ans:=ans div x*(x-1);
                        //这里也涉及到运算顺序的问题
        exit(ans mod tt);
    end;
    
    function mul(a,b:longint):longint;
    var ans,w:int64;
    begin
        ans:=1;w:=a mod tt;
        while b<>0 do
        begin
            if b and 1=1 then ans:=(ans*w) mod tt;
            w:=(w*w) mod tt;
            b:=b >> 1;
        end;
        exit(ans);
    end;
    
    function solve:longint;
    var i:longint;
        ans:int64;
    begin
        ans:=0;
        for i:=1 to trunc(sqrt(n)) do if n mod i=0 then
        begin
            ans:=(ans+phi(n div i)*mul(n,i-1)) mod tt;
            if i*i<>n then ans:=(ans+phi(i)*mul(n,n div i-1)) mod tt;
        end;
        exit(ans);
    end;
    
    begin
        readln(test);
            build;
            for t:=1 to test do
        begin
            readln(n,tt);
            writeln(solve);
        end;
    end.
  • 相关阅读:
    洛谷—— P1187 3D模型
    商铺项目(Redis缓存)
    商铺项目(使用DES加密配置信息)
    Linux下tomcat启动项目原因排查
    商铺项目(商品详情页开发)
    商铺项目(店铺详情页开发)
    商铺项目(店铺列表开发)
    商铺项目(首页前端开发)
    商铺项目(首页后台开发)
    商铺项目(商品类别模块二)
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4402049.html
Copyright © 2011-2022 走看看