【洛谷 P4980】 【模板】Pólya 定理

简单的写一下吧,Polya定理就是用来求等价类的数目的。
什么是等价类?经过某些置换操作能相等的两个的状态属于同一个等价类。
然后是一些基本的定理,
等价类的数目\(C\)为置换群的不动点的平均值,
\(C=\frac{1}{|G|}\sum _{f\in G}k^{m(f)}\)
其中,\(G\)为置换群,\(f\)为其中的一种置换,\(m(f)\)表示把置换\(f\)看成\(m(f)\)\(f\)的乘积(可以理解为循环节),\(k\)表示颜色的种类数。
显然本题的置换群就是\({旋转0个,旋转1个,...,旋转n个}\)
考虑旋转\(k\)个的循环节\(p\),显然\(p|k\),同时\(p|n\),所以旋转\(k\)个的贡献就是\(n^{gcd(k,n)}\)
那么最终答案就是\(\frac{1}{n}\sum_{i=0}^{n-1}n^{gcd(i,n)}\)
直接求显然是\(O(nlogn)\)
\(n\)的约数为\(m\)个,考虑到不同\(gcd\)的数量只有\(m\)个,于是枚举约数\(d\)
\(k=e*d\),显然满足\(gcd(k,n)=d\)\(e\)要与\(\frac{n}{d}\)互质,那么这样的\(k\)\(\varphi{\frac{n}{d}}\)
于是最终答案就是\(\frac{1}{n}\sum_{d|n}n^d\varphi{\frac{n}{d}}\)

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int T, n;
int gcd(int a, int b){
	return !b ? a : gcd(b, a % b);
}
long long ans;
long long fast_pow(long long a, int k){
	long long ans = 1;
	while(k){
		if(k & 1) ans = ans * a % MOD;
		a = a * a % MOD; k >>= 1;
	}
	return ans;
}
int phi(int x){
	if(x == 1) return 1;
	int y = x;
	int p = sqrt(x);
	for(int i = 2; i <= p && x != 1; ++i)
		if(x % i == 0){
			y = y / i * (i - 1);
			while(x % i == 0) x /= i;
		}
	if(x != 1) y = y / x * (x - 1);
	return y;
}
int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d", &n); ans = 0;
		int p = sqrt(n);
		for(int i = 1; i <= p; ++i)
			if(n % i == 0){
				ans = (ans + fast_pow(n, i) * phi(n / i)) % MOD;
				if(i * i != n) ans = (ans + fast_pow(n, n / i) * phi(i)) % MOD;
			}
		printf("%lld\n", ans * fast_pow(n, MOD - 2) % MOD);
	}
	return 0;
}
posted @ 2021-09-15 20:28  Qihoo360  阅读(70)  评论(0编辑  收藏  举报
You're powerful!