1. 程式人生 > >POJ2154 Color polya定理+歐拉定理

POJ2154 Color polya定理+歐拉定理

顏色 ring lld ref targe 技術分享 math while cstring

由於這是第一天去實現polya題,所以由易到難,先來個鋪墊題(假設讀者是看過課件的,不然可能會對有些“顯然”的地方會看不懂):

POJ1286 Necklace of Beads :有三種顏色,問可以翻轉,可以旋轉的染色方案數,n<24。

1,n比較小,惡意的揣測出題人很有可能出超級多組數據,所以先打表。

2,考慮旋轉:

for(i=0;i<n;i++)  sum+=pow(n,gcd(n,i));  

3,考慮翻轉:

if(n&1)  sum+=n*pow(3,n/2+1) ;  
else {  
      sum+=n/2
*pow(3,n/2) ; sum+=n/2*pow(3,n/2+1) ; }

4,除以總置換數(n+n/2+n/2):

sum/=(2*n);

5,終極代碼:

技術分享圖片
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
#define ll long long
ll ans[30];
ll gcd(ll a,ll b) {  
if(b==0) return a; return gcd(b,a%b); } ll pow(ll a,ll x) { ll res=1; while(x){ if(x&1) res*=a; x>>=1; a*=a; } return res; } int main() { ll n,i,sum; for(n=1;n<=23;n++){ sum=0; for(i=0;i<n;i++) sum+=pow(3,gcd(n,i));
if(n&1) sum+=n*pow(3,n/2+1) ; else { sum+=n/2*pow(3,n/2) ; sum+=n/2*pow(3,n/2+1) ; } ans[n]=sum/n/2; } while(~scanf("%lld",&n)){ if(n==-1) return 0; printf("%lld\n",ans[n]); } return 0; }
View Code

----------------------------------------------------分界線--------------------------------------------------------------------------------

POJ2154 Color: 求可以旋轉,不可以翻轉的置換,n個珠子,n種顏色,答案mod K,n<1e9。

那麽本題只考慮旋轉,則:

for(i=0;i<n;i++)  ans+=pow(n,gcd(n,i));  
ans/=n;

之前莫比烏斯那裏,我們常用技巧是合並。 這裏考慮gcd相同的合並。(做多了還是有點靈感滴,yeah)。

得到:技術分享圖片

解決這個公式需要:快速冪+歐拉公式+一些素數的常識。

1,快速冪不說了,註意先模運算。

2,歐拉公式,枚舉L,即n的素因子,然後根據phi=L*(1-1/p1)*(1-1/p2)...得到歐拉函數。

3,素數常識,在這裏指的是一個數n的素因子最多有一個大於根號n,所以一直除,把根號n前的素數都除完了,留下的一定是大於根號n的一個素數。

//可以線篩一部分歐拉函數出來,不夠的再枚舉素數;枚舉的話不超過根號個,所以復雜度不會太高。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000;
int ans, Mod;
int pri[maxn+10],cnt,vis[maxn+10],phi[maxn+10];
int qpow(int a,int x)
{
    int res=1;a%=Mod;//這裏a一定要除一下,不然會超int,豬啊。 
    while(x){
        if(x&1) res=res*a%Mod;
        x>>=1; a=a*a%Mod;
    } return res%Mod;
}
void prime()
{
    phi[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&pri[j]*i<=maxn;j++) {
            vis[pri[j]*i]=1;
            if(i%pri[j]==0) {
                phi[i*pri[j]]=phi[i]*pri[j];
                break;
            }
            else phi[i*pri[j]]=phi[i]*(pri[j]-1);
        }
    }
}
int Phi(int x)
{
    if(x<=maxn) return phi[x]%Mod; 
    int res=x;
    for(int i=1;pri[i]*pri[i]<=x;i++)
      if(x%pri[i]==0){
          res=(res-res/pri[i]);
          while(x%pri[i]==0) x/=pri[i];
     }
    if(x!=1) res=(res-res/x);
    return res%Mod;
}
int main()
{
    int n,T; prime();
    scanf("%d",&T);
    while(T--){
        ans=0; scanf("%d%d",&n,&Mod); 
        for(int i=1;i*i<=n;i++){
            if(n%i!=0) continue;
            ans=(ans+qpow(n,i-1)*Phi(n/i))%Mod;
            if(i*i!=n) ans=(ans+qpow(n,n/i-1)*Phi(i))%Mod;
        }
        printf("%d\n",ans);
    } return 0;
}

POJ2154 Color polya定理+歐拉定理