POJ 2154 color 发表于 2018-02-09 | 分类于 题解 , poj | 题目链接POJ 2154 color 题解对于一个n元素环染色,先考虑旋转,置换的总数是n个旋转k个元素后构成的循环数,即轮换数为$gcd(k,n)$根据polay定理,方案数为对与于这个式子可以化为 欧拉+快速幂 代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>int n,p;const int maxn = 1000000007;inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0') x=x*10+c-'0',c=getchar(); return x*f;}const int maxm = 1000005;int pri[maxm],tot=0;bool vis[maxm];int phi(int x) { int ret=x;; for(int i=1;pri[i]<=sqrt(x);i++) if(x%pri[i]==0) { ret=(ret-ret/pri[i]); while(x%pri[i]==0)x/=pri[i]; } if(x!=1)ret=(ret-ret/x); return ret%p;}void getpre() { for(int i=2;i<=1000000;i++) { if(!vis[i])pri[++tot]=i; for(int j=1;j<=tot&&pri[j]*i<=1000000;j++) { vis[pri[j]*i]=1; if(i%pri[j]==0)break; } }}int qpow(int n,int cnt) { int ret=1,tmp=n;tmp%=p; while(cnt) { if(cnt&1) ret=(tmp*ret)%p; tmp=tmp*tmp%p; cnt>>=1; } return ret;}void dec(int n) { int ans=0; for(int i=1;i*i<=n;++i) { if(i*i==n)ans=(ans+phi(i)*qpow(n,i-1))%p; else if(!(n%i)) { ans=(ans+qpow(n,i-1)*phi(n/i)+qpow(n,n/i-1)*phi(i))%p; } } printf("%d\n",ans);}int main() { getpre(); int cnt=read();// for(int i=1;i<=cnt;++i) {// printf("%d ",phi[i]);// } for(;cnt--;) { n=read(),p=read(); dec(n); } return 0;}