题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4423
题意:
环上N个点,2种颜色,只有旋转置换,有多少种染色方法
Polya定理
设\(G=\left \{ a_1,a_2,\cdots ,a_g \right \}\)是n 个对象的一个置换群,用k 种颜色去染这n 个对象,若一种染色方案在群G 的作
用下变为一种方案,则这两个方案当作是同一种方案,这样的不同染色方案数为:
用下变为一种方案,则这两个方案当作是同一种方案,这样的不同染色方案数为:
$$L=\frac{1}{| G|}\sum_{i=1}^{|G|}k^{C(a_i)}$$
\(C(a_i)\)为置换的循环节,\(|G|\)表示群的置换数。
对于n 个位置的手镯,有n 种旋转置换和n 种翻转置换
对于旋转置换:
\(C(a_i)=\gcd (n,i)\),i 表示旋转i 颗宝石以后。\(i=0\) 时\(\gcd(n,0)=n\)
对于翻转置换:
如果\(n\)为偶数:则有\(\frac{n}{2}\)个置换\(C(a)=\frac {n}{2}\),有\(\frac{n}{2}\)个置换\(C(a)=\frac {n}{2}+1\)
题目只有旋转置换,但要求\(1\leqslant n\leqslant 10^9\),直接算肯定会超时,所以可以枚举n的因子i,满足\(\\gcd(n,x)=i,1\leqslant x\leqslant n\)的x的数量为\(\phi(\frac{n}{i})\),\(\phi\)为欧拉函数如果\(n\)为奇数:则有\(n\)个置换\(C(a)=\frac {n}{2}+1\)
所以公式可化为
$$L=\frac{1}{n}\sum_{i|n}\phi (\frac{n}{i})\cdot k^i$$
其中幂的运算用快速幂,最后答案要求mod1000000007,所以还要求\(nx = 1( mod 1000000007)\) 的x值,就是逆元
对n的因子的枚举可以只枚举到\(\sqrt{n}\),因为\(i|n\),则\(\frac{n}{i}|n\)
最终复杂度为\(O(k^2)\),其中k为N的约数个数。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL long long
#define N 100005
#define INF 1<<30
#define MOD 1000000007
LL euler(LL n) {
LL ans = n;
for(int i = 2; i*i <= n; i++) {
if(n % i == 0) {
ans -= ans/i;
while(n % i == 0)
n /= i;
}
}
if(n > 1)ans -= ans/n;
return ans;
}
LL inv(LL a,LL m)//求ax = 1( mod m) 的x值,就是逆元(0<a<m)
{
if(a == 1)return 1;
return inv(m%a,m)*(m-m/a)%m;
}
LL pm(LL a,LL b) {
LL ret=1;
while(b) {
if(b&1)ret=(ret*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return ret;
}
int main() {
//freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
//freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
int t;
LL n;
scanf("%d",&t);
while(t--) {
scanf("%lld",&n);
LL ans=0;
for(int i=1; i*i<=n; ++i) {
if(n%i==0) {
ans=(ans+pm(2,i)*euler(n/i))%MOD;
if(i!=n/i){
ans=(ans+pm(2,n/i)*euler(i))%MOD;
}
}
}
printf("%lld\n",((ans)*inv(n,MOD))%MOD);
}
return 0;
}