P4980 模板Polya定理

Posted ppprseter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4980 模板Polya定理相关的知识,希望对你有一定的参考价值。

P4980 【模板】Polya定理

题目描述

给定一个(n)个点,(n)条边的环,有(n)种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对(10^9+7)取模

注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同

输入输出格式

输入格式:

第一行输入一个(t),表示有(t)组数据

第二行开始,一共(t)行,每行一个整数(n),意思如题所示。

输出格式:

(t)行,每行一个数字,表示染色方案数对(10^9+7)取模后的结果

说明

(n leq 10^9,t leq 10^3)


注意置换只有(n)个,表示旋转的度数,没有翻转。

那么一个旋转(i)个点的置换的循环个数应该为(gcd(i,m))

带到(Polya)定理里面去,方案数为

[frac{1}{n}sum_{i=1}^n n^{gcd(i,n)}]

[=frac{1}{n}sum_{i=1}^n n^ksum_{k=1}^n[gcd(i,n)=k]]

[=frac{1}{n}sum_{kmid n} n^ksum_{k=1}^n[gcd(i,n)=k]]

[=sum_{kmid n} n^{k-1}sum_{k=1}^{frac{n}{k}}[gcd(i,n)=1]]

[=sum_{k|n}n^{k-1}varphi(frac{n}{k})]

然后直接暴力搞,复杂度是常数很小的(O(Tn^{frac{3}{4}}))


Code:

#include <cstdio>
const int mod=1e9+7;
int Euler(int n)
{
    int phi=n;
    for(int i=2;i*i<=n;i++)
        if(n%i==0)
        {
            phi=phi-phi/i;
            while(n%i==0) n/=i;
        }
    if(n!=1) phi=phi-phi/n;
    return phi;
}
#define mul(a,b) (1ll*(a)*(b)%mod)
#define add(a,b) ((a+b)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int Polya(int n)
{
    int ans=0;
    for(int i=1;i*i<=n;i++)
    {
        if(n%i) continue;
        ans=add(ans,mul(qp(n,i-1),Euler(n/i)));
        if(i*i!=n)
            ans=add(ans,mul(qp(n,n/i-1),Euler(i)));
    }
    return ans;
}
int main()
{
    int n,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        printf("%d
",Polya(n));
    }
    return 0;
}

2018.12.21

以上是关于P4980 模板Polya定理的主要内容,如果未能解决你的问题,请参考以下文章

P4980 模板Polya定理

poj2409(polya 定理模板)

Luogu4980 模板Polya定理(Polya定理+欧拉函数)

poj1286 Necklace of Beads—— Polya定理

积累Burnside引理和Polya定理

Polya 定理入门[Burnside引理,Polya定理,欧拉函数]