【洛谷 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章