正题
题目链接:https://www.luogu.com.cn/problem/P4980
题目大意
nnn个物品图上mmm种颜色,求在可以旋转的情况下本质不同的涂色方案。
解题思路
既然是群论基本题就顺便写一下刚刚了解到的相关知识把(顺便消磨一下时间
一个群(G,×)(G,\times )(G,×)定义为一个在运算×\times×下满足以下条件的集合
- 封闭性:若存在a,b∈Ga,b\in Ga,b∈G那么有a×b∈Ga\times b\in Ga×b∈G
- 交换律:若有a,b,c∈Ga,b,c\in Ga,b,c∈G那么有(a×b)×c=a×(b×c)(a\times b)\times c=a\times (b\times c)(a×b)×c=a×(b×c)
- 单位元:群中∃e∈G\exist e\in G∃e∈G满足∀x∈G\forall x\in G∀x∈G都有x×e=xx\times e=xx×e=x
- 逆元:对于∀x∈G\forall x\in G∀x∈G都有一个唯一元素y∈Gy\in Gy∈G且x×y=ex\times y=ex×y=e
然后中间一些东西很多很杂这里不多说了,直接到置换部分。
一般来说规定置换第一行为(1,2,3...)(1,2,3...)(1,2,3...),那么定义一个置换σ=(g1,g2,g3,...)\sigma=(g_1,g_2,g_3,...)σ=(g1,g2,g3,...)。如果一个置换作用与一个排列aaa,一般写为σ(a)=b\sigma(a)=bσ(a)=b的话,就有bi=agib_i=a_{g_i}bi=agi。需要注意的是对于一个置换两次后相当与使用了另一个置换。(也就是置换只能生效一次
然后就是Burnside\text{Burnside}Burnside引理了,对于一个置换群GGG,若GGG作用与一个集合XXX时,集合XXX中本质不同的元素个数为
1∣G∣∑f∈GC(f)\frac{1}{|G|}\sum_{f\in G}C(f)∣G∣1f∈G∑C(f)
其中C(f)C(f)C(f)表示XXX的所有元素中对于置换fff的不动点数量。
而Polya\text{Polya}Polya定理就是建立在Burnside\text{Burnside}Burnside引理上的,对于一个置换fff,定义它的循环节数量为T(f)T(f)T(f),用mmm种颜色染色时方本质不同的染色方案数就是
1∣G∣∑f∈GmT(f)\frac{1}{|G|}\sum_{f\in G}m^{T(f)}∣G∣1f∈G∑mT(f)
也就是mT(f)=C(f)m^{T(f)}=C(f)mT(f)=C(f),这个很显然,因为每个循环节涂成一种颜色就是一个不动点。
回到这题的旋转来,我们可以将其视为nnn个不同的置换构成的一个置换群。对于旋转iii步,它的循环节数量就是gcd(n,i)gcd(n,i)gcd(n,i),也就是我们要求
1n∑i=0n−1mgcd(n,i)\frac{1}{n}\sum_{i=0}^{n-1}m^{gcd(n,i)}n1i=0∑n−1mgcd(n,i)
枚举一下gcd(n,i)gcd(n,i)gcd(n,i)
1n∑d∣nmd∑i=1nd[gcd(nd,i)==1]\frac{1}{n}\sum_{d|n}m^d\sum_{i=1}^{\frac{n}{d}}[gcd(\frac{n}{d},i)==1]n1d∣n∑mdi=1∑dn[gcd(dn,i)==1]
哦对啊好像有m=nm=nm=n
1n∑d∣nndφ(nd)=∑d∣nnd−1φ(nd)\frac{1}{n}\sum_{d|n}n^d\varphi(\frac{n}{d})=\sum_{d|n}n^{d-1}\varphi(\frac{n}{d})n1d∣n∑ndφ(dn)=d∣n∑nd−1φ(dn)
这个时间复杂度大概是O(Tn34)O(Tn^{\frac{3}{4}})O(Tn43)的,但是因为约数个数远到不了n\sqrt nn所以你可以把它视为常数比较大的O(Tn)O(T\sqrt n)O(Tn)?
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll P=1e9+7;
ll T,n,ans;
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans;
}
ll phi(ll x){ll ans=x;for(ll i=2;i*i<=x;i++){if(x%i)continue;while(x%i==0)x/=i;ans=ans/i*(i-1);}if(x>1)ans=ans/x*(x-1);return ans;
}
ll calc(ll x)
{return phi(x)*power(n,n/x-1)%P;}
signed main()
{scanf("%lld",&T);while(T--){scanf("%lld",&n);ans=0;for(ll i=1;i*i<=n;i++){if(n%i)continue;ans=(ans+calc(i))%P;if(i*i!=n)ans=(ans+calc(n/i))%P;}printf("%lld\n",ans);}return 0;
}