1. 程式人生 > >POJ 2154 Color

POJ 2154 Color

print gcd phi clu har cst line ans 總數

題目鏈接

POJ 2154 color

題解

對於一個n元素環染色,先考慮旋轉,置換的總數是n個
旋轉k個元素後構成的循環數,即輪換數為\(gcd(k,n)\)
根據polay定理,方案數為\[\dfrac{1}{n}\sum_{k=1}^nn^{gcd(k,n)}\]
對與於這個式子可以化為
\[\dfrac{1}{n} \sum_{d|n}n^d\sum_{k=1}^{n}[gcd(k,n)==d]\]
\[\sum_{d|n}n^{d-1}\sum_{k=1}^{n}[gcd(\dfrac{k}{d},\dfrac{n}{d})==1]\]
\[\sum_{d|n}n^{d-1}\sum_{k=1}^{\dfrac{n}{d}}[gcd(k,\dfrac{n}{d})==1]\]


\[\sum_{d|n}n^{d-1}*\phi(\dfrac{n}{d})\]
歐拉+快速冪

代碼

#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; }

POJ 2154 Color