1. 程式人生 > >【數論&Polya定理】圖的同構 BZOJ 1488

【數論&Polya定理】圖的同構 BZOJ 1488

#include<cstdio> #include<algorithm> using namespace std; #define MAXN 60 #define MO 997 int n,ans; int G[MAXN+5][MAXN+5],inv[MO],Pow[MAXN+5][MAXN+5],fac[MAXN+5]; int PowMod(int a,int b) { int ret=1; while(b) { if(b&1) ret=ret*a%MO; a=a*a%MO; b>>=1
; } return ret; } int gcd(int a,int b) { while(b) { int t=a; a=b;b=t%b; } return a; } void Pre() { fac[0]=1; for(int i=1;i<=MAXN;i++) { fac[i]=i*fac[i-1]%MO; Pow[i][0]=1; for(int j=1;j<=MAXN;j++) Pow[i][j]=Pow[i][j-1
]*i%MO,G[i][j]=gcd(i,j); } inv[1]=1; for(int i=2;i<MO;i++) inv[i]=(MO-MO/i)*inv[MO%i]%MO; } int val[MAXN],cnt[MAXN],c;//val:某一迴圈的長度,cnt:該迴圈在此類置換中出現的數量。 void dfs(int s,int left) { if(left==0) { int sum1=0,sum2=1;//sum1:統計該置換下邊的著色方案 ,sum2:該形式的置換的數目 for(int i=1;i<=c;i++) { sum1+=val[i]/2
*cnt[i]+cnt[i]*(cnt[i]-1)/2*val[i]; sum2=sum2*fac[cnt[i]]*Pow[val[i]][cnt[i]]%MO; for(int j=i+1;j<=c;j++) sum1+=cnt[i]*cnt[j]*G[val[i]][val[j]]; } sum2=inv[sum2]*fac[n]%MO; ans=(ans+sum2*PowMod(2,sum1))%MO; return; } if(left<s) return; dfs(s+1,left); for(int i=1;i*s<=left;i++) { val[++c]=s,cnt[c]=i; dfs(s+1,left-i*s); c--; } } int main() { Pre(); scanf("%d",&n); dfs(1,n); ans=ans*inv[fac[n]]%MO; printf("%d\n",ans); }