[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.
时间: 2024-10-09 15:02:11

[POJ1286&POJ2154&POJ2409]Polya定理的相关文章

poj2409 polya定理经典问题

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cstdio> #include<set> #include<queue> #include<map> #define I

POJ2154 Color(Polya定理)

Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11654   Accepted: 3756 Description Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of the nec

POJ2154 Color polya定理+欧拉定理

由于这是第一天去实现polya题,所以由易到难,先来个铺垫题(假设读者是看过课件的,不然可能会对有些“显然”的地方会看不懂): POJ1286 Necklace of Beads :有三种颜色,问可以翻转,可以旋转的染色方案数,n<24. 1,n比较小,恶意的揣测出题人很有可能出超级多组数据,所以先打表. 2,考虑旋转: for(i=0;i<n;i++) sum+=pow(n,gcd(n,i)); 3,考虑翻转: if(n&1) sum+=n*pow(3,n/2+1) ; else {

POJ1286 Necklace of Beads【Polya定理】

题目链接: http://poj.org/problem?id=1286 题目大意: 给定3种颜色的珠子,每种颜色珠子的个数均不限,将这些珠子做成长度为N的项链. 问能做成多少种不重复的项链,最后的结果不会超过int类型数据的表示范围.并且两 条项链相同,当且仅当两条项链通过旋转或是翻转后能重合在一起,且对应珠子的颜 色相同. 解题思路: 这道题和POJ2409是一样的题目,只不过这道题规定了颜色数目. Polya定理的应用.先来看Polya定理. Polya定理:设 G = {a1,a2,-,

[POJ2409]Let it Bead - Polya定理

[POJ2409]Let it Bead Time Limit: 1000MS   Memory Limit: 65536K Description "Let it Bead" company is located upstairs at 700 Cannery Row in Monterey, CA. As you can deduce from the company name, their business is beads. Their PR department found

【poj2154】Color Polya定理+欧拉函数

题目描述 $T$ 组询问,用 $n$ 种颜色去染 $n$ 个点的环,旋转后相同视为同构.求不同构的环的个数模 $p$ 的结果. $T\le 3500,n\le 10^9,p\le 30000$ . 题解 Polya定理+欧拉函数 根据 poj2409 中得到的结论,答案为: $\frac{\sum\limits_{i=1}^nn^{\gcd(i,n)}}n=\sum\limits_{i=1}^nn^{\gcd(i,n)-1}$ 由于 $n$ 有 $10^9$ 之大,因此考虑优化这个式子. 枚举

【Polya定理】poj1286 Necklace of Beads

Polya定理:设G={π1,π2,π3........πn}是X={a1,a2,a3.......an}上一个置换群,用m中颜色对X中的元素进行涂色,那么不同的涂色方案数为:1/|G|*(mC(π1)+mC(π2)+mC(π3)+...+mC(πk)). 其中C(πk)为置换πk的循环节的个数. Polya定理的基础应用. 你得算出旋转和翻转时,每种置换的循环节数. 旋转时,每种置换的循环节数为gcd(n,i): 翻转时,若n为奇数,共有n个循环节数为n+1>>1的置换, 若n为偶数,共有n

POJ2154 Color【Polya定理】【欧拉函数】【整数快速幂】

题目链接: http://poj.org/problem?id=2154 题目大意: 给定 N 种颜色的珠子,每种颜色珠子的个数均不限,将这些珠子做成长度为 N 的项链. 问能做成多少种不重复的项链,最后结果对 P 取模.并且两条项链相同,当且仅当两条 项链通过旋转后能重合在一起,且对应珠子的颜色相同. 解题思路: Polya定理的应用.先来看Polya定理. Polya定理:设 G = {a1,a2,-,ag}是 N 个对象的置换群,用 M 种颜色给这 N 个 对象着色,则不同的着色 方案数为

poj2409:Let it Bead(置换群 polya定理)

题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案. 学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展. burnside定理告诉我们不同染色方案数是每种置换的不变元素个数除以置换总数,而polya定理就是在这个基础上用公式计算出置换的不变元素个数.而且polya定理非常好理解,我们要让元素不变,所以对于每个循环节我们要染一样的颜色,有m种颜色,c(pk)个循环节,于是每种置换的不变元素个数就是m^c(pk). 对于这道题