题目:luogu4980.
题目大意:给定一个长度为 n n n的环,用 n n n种颜色染色,求本质不同(旋转后相同算一种)的染色方案数.
数据组数 T ≤ 1 0 3 T\leq 10^3 T≤103, 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1≤n≤109,答案对 1 0 9 + 7 10^9+7 109+7取模.
具体Polya定理相关内容参考群论与置换群入门.
考虑将旋转放入一个置换群,那么置换群中的元素有循环 0 0 0位,循环 1 1 1位,循环 2 2 2位…循环 n − 1 n-1 n−1位,其中循环 0 0 0为可以看成循环 n n n位.
然后使用Ploya定理,设 C ( A ) C(A) C(A)表示 A A A可以拆分的轮换数,那么有:
a n s = 1 n ∑ i = 1 n n C ( A i ) ans=\frac{1}{n}\sum_{i=1}^{n}n^{C(A_i)} ans=n1i=1∑nnC(Ai)
现在的问题是如何计算每一个置换可以拆成几个轮换.
考虑循环 a a a位如何计算可以拆解的轮换数.容易发现拆解出来的每个轮换大小都是相等的,可以用 n n n除掉轮换大小,问题变为求轮换大小.
显然轮换大小应该是以下方程中 x x x的最小正整数解:
a x ≡ 0 ( m o d n ) ax\equiv 0\,\,(mod\,\,n) ax≡0(modn)
可以转化为以下方程中 x x x的最小正整数解:
a x = n y ax=ny ax=ny
容易发现 x x x为最小正整数解时, a x = n y = l c m ( n , a ) ax=ny=\mathrm{lcm}(n,a) ax=ny=lcm(n,a).
于是轮换数就是:
n l c m ( n , a ) a = n a l c m ( n , a ) = gcd ( n , a ) \frac{n}{\frac{\mathrm{lcm}(n,a)}{a}}=\frac{na}{\mathrm{lcm}(n,a)}=\gcd(n,a) alcm(n,a)n=lcm(n,a)na=gcd(n,a)
也就是说对于一个循环位移 a a a位的置换 A A A有 C ( A ) = gcd ( n , a ) C(A)=\gcd(n,a) C(A)=gcd(n,a).
那么整道题目的答案为:
1 n ∑ i = 1 n n gcd ( n , i ) \frac{1}{n}\sum_{i=1}^{n}n^{\gcd(n,i)} n1i=1∑nngcd(n,i)
可是 n n n是 1 0 9 10^9 109级别的数据,并不能暴力枚举…
所以开始推式子:
1 n ∑ i = 1 n n gcd ( n , i ) = 1 n ∑ d ∣ n n d ∑ i = 1 n d [ gcd ( n d , i ) = 1 ] = 1 n ∑ d ∣ n n d ϕ ( n d ) = ∑ d ∣ n n d − 1 ϕ ( n d ) \frac{1}{n}\sum_{i=1}^{n}n^{\gcd(n,i)}\\ =\frac{1}{n}\sum_{d|n}n^{d}\sum_{i=1}^{\frac{n}{d}}[\gcd(\frac{n}{d},i)=1]\\ =\frac{1}{n}\sum_{d|n}n^{d}\phi(\frac{n}{d})\\ =\sum_{d|n}n^{d-1}\phi(\frac{n}{d}) n1i=1∑nngcd(n,i)=n1d∣n∑ndi=1∑dn[gcd(dn,i)=1]=n1d∣n∑ndϕ(dn)=d∣n∑nd−1ϕ(dn)
这个东西计算起来时间复杂度是 O ( τ ( n ) n ) O(\tau(n)\sqrt{n}) O(τ(n)n),不能过.
可以先把 n n n的质因数分解出来,然后每次求它的某个因数的 ϕ \phi ϕ值时,可以直接暴力枚举 n n n的质因数去算,时间复杂度 O ( T ( τ ( n ) log n ) ) O(T(\tau(n)\log n)) O(T(τ(n)logn)).
代码如下:
#include
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=50,mod=1000000007;
int add(int a,int b,int p=mod){return a+b>=p?a+b-p:a+b;}
int sub(int a,int b,int p=mod){return a-b<0?a-b+p:a-b;}
int mul(int a,int b,int p=mod){return (LL)a*b%p;}
void sadd(int &a,int b,int p=mod){a=add(a,b,p);}
void ssub(int &a,int b,int p=mod){a=sub(a,b,p);}
void smul(int &a,int b,int p=mod){a=mul(a,b,p);}
int Power(int a,int k,int p=mod){int res=1;for (;k;k>>=1,smul(a,a,p)) if (k&1) smul(res,a,p);return res;}
int n,d[N+9],cd;
void Get_d(int n){
cd=0;
int now=n;
for (int i=2;i*i<=n;++i)
if (now%i==0)
for (d[++cd]=i;now%i==0;now/=i);
if (now>1) d[++cd]=now;
}
int Get_phi(int n){
int res=n;
for (int i=1;i<=cd;++i)
if (n%d[i]==0) res=res/d[i]*(d[i]-1);
return res;
}
int ans;
Abigail into(){
scanf("%d",&n);
}
Abigail work(){
ans=0;
Get_d(n);
for (int i=1;i*i<=n;++i)
if (n%i==0){
sadd(ans,mul(Power(n,i-1),Get_phi(n/i)));
if (i*i^n) sadd(ans,mul(Power(n,n/i-1),Get_phi(i)));
}
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}