Polya定理
置換群中的概念(數學表達):
\(M=\frac{1}{G}\sum\limits_{i=1}^g m^c\)
G:表示置換的個數,m表示顏色種類(方案中不一定使用全部顏色),c表示每種置換的循環節個數
注釋:循環節個數解釋:
\[\left[ \begin{array}{cc} 1&2&3&4\\ 1&4&3&2 \end{array} \right] \]
這為三個循環節,分別是[1],[3],[2,4];
\[\left[ \begin{array}{cc} 1&2&3&4\\ 4&1&2&3 \end{array} \right] \]
這是一個循環[1,2],[2,3],[3,4],[4,1],可以合並成[1];
目前認識到:置換分為兩大類\(\begin{cases}\text{旋轉:旋轉i步的循環為gcd(i,n)}\\ \text{翻轉:}\begin{cases}\text{n為奇數,c=n+1/2}\\\text{n為偶數}\frac{1}{2}c=n/2,\frac{1}{2}c=n/2+1\end{cases} \end{cases}\)
證明待補充
例題:
1.poj2409
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
inline int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
inline int poww(int a,int b){
int ans=1;
while(b){
if(b&1)ans*=a;
b>>=1;
a*=a;
}
return ans;
}
int main(){
while(1){
scanf("%d%d",&m,&n);
if(m==0&&n==0)break;
int c=0;
for(int i=0;i<n;++i)c+=poww(m,gcd(i,n));
if(n&1)c+=n*poww(m,(n+1)/2);
else c+=n/2*poww(m,n/2)+n/2*poww(m,n/2+1);
cout<<c/(2*n)<<endl;
}
return 0;
}
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int t,n,p,tot,cnt;
int prime[1000000],v[1000000];
inline void pre(){
for(int i=2;i<=100000;++i){
if(!v[i]){
prime[++tot]=i;
v[i]=i;
}
for(int j=1;j<=tot;++j){
if(prime[j]*i>100000||prime[j]>v[i])break;
v[i*prime[j]]=prime[j];
}
}
}
inline int poww(int a,int b){
int ans=1;
while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans%p;
}
inline int euler(int x){
int ans=x;
for(int i=1;i<=tot&&prime[i]*prime[i]<=x;++i){
if(x%prime[i]==0){
ans=ans/prime[i]*(prime[i]-1);
while(x%prime[i]==0)x/=prime[i];
}
}
if(x>1)ans=ans/x*(x-1);
return ans;
}
int main(){
pre();
cin>>t;
for(int i=1;i<=t;++i){
cin>>n>>p;
int c=0;
for(int j=1;j<=sqrt(n);++j){
if(n%j==0){
c=(c+euler(n/j)%p*poww(n%p,j-1)%p)%p;
if(j*j!=n)c=(c+euler(j)%p*poww(n%p,n/j-1)%p)%p;
}
}
cout<<c%p<<endl;
}
return 0;
}
