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^k\sum_{k=1}^n[\gcd(i,n)=k] \]

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

\[=\sum_{k\mid 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\n",Polya(n));
    }
    return 0;
}

2018.12.21

posted @ 2018-12-21 13:33  露迭月  阅读(216)  评论(0编辑  收藏  举报