1. 程式人生 > >bzoj 2601: [Jsoi2011]同分異構體計數

bzoj 2601: [Jsoi2011]同分異構體計數

bzoj desc 變換 gcd ide sca oid tor 簡單圖

Description

Antonio 最近對有機化學比較感興趣,他想請你幫助他快速計算出某種烴類的同分異 構體的數目。 為了表述方便,我們作出如下定義: 環烷烴: 具有n 個碳原子的環烷烴可以表示成一張具有n 個頂點n 條邊的無向連通 簡單圖(基環+外向樹)。每個頂點的度數不超過 4。 M-環烷烴:至多有m 個頂點在環上的環烷烴。(註意環上至少有 3 個頂點,因為 任意兩個頂點之間至多只能有1 條邊)。 同構:假設結構A和結構B 均具有n 個碳原子,A和B 同構當且僅當能夠對A和 B 中的每個碳原子都按照 1~n 編號,使得對於編號為 v1 和 v2 的兩個碳原子,他
們在 A中存在邊相連當且僅當他們在 B中存在邊相連。(換言之,A和 B對應的圖 同構)。 現在,給出n, m,Antonio 希望你幫助他統計有多少種互不同構的含有n 個碳原子的 m-環烷烴。由於這個數量可能很大,你只需要輸出它對p 的余數。(p是一個素數)。 在本題中,我們不考慮某結構在化學上是否能夠穩定存在,也不考慮其他的異構方式。

Input

輸入文件只有一行,用空格隔開的三個整數n, m, p 。保證有m <=n,p為素數。

Output

輸出文件有且僅有一行,表示具有n 個碳原子的互不同構的m-環烷烴的數量,對 p的 余數。 先處理出根的度為2,其余點度<=4的無標號有根樹的方案數 環有旋轉和翻轉兩種變換,由於m>=3,構成的置換群階為2m,用burnside引理處理 旋轉k(0<=k<m)步可以形成gcd(m,k)個等價類,每個等價類包含m/gcd(m,k)個位置 旋轉+翻轉需要分奇偶處理: 若m為奇數,則有m個這種置換,形成(m+1)/2個等價類,其中一個等價類包含1個位置,其余包含2個位置 若m為偶數   則有m/2個置換形成m/2個等價類,每個等價類包含2個位置   另有m/2個置換形成m/2+1個等價類,其中兩個等價類包含1個位置,其余包含2個位置
#include<cstdio>
typedef unsigned 
long long u64; typedef unsigned int u32; int n,m; u32 P; int gcd(int a,int b){ for(int c;b;c=a,a=b,b=c%b); return a; } int phi(int n){ int v=n; for(int i=2;i*i<=n;++i)if(n%i==0){ do n/=i;while(n%i==0); v=v/i*(i-1); } if(n>1)v=v/n*(n-1); return
v; } inline u32 fix(int a){ return a+(a>>31&P); } struct num{ u32 x; num(u32 a=0):x(a){} num operator+(num w){return fix(x+w.x-P);} num operator*(num w){return u64(x)*w.x%P;} void operator+=(num w){x=fix(x+w.x-P);} }; num s[5][1007],gs[11],iv[117],f0[57][1007],f1[57][1007],ans; void cal(int m,int n){ int g=gcd(n,m); num v=0; for(int d=1;d<=g;++d)if(g%d==0)v+=f0[m/d][n/d]*phi(d); v+=f1[m][n]*m; // printf("%d,%d:%d\n",m,n,v*iv[m*2]); ans+=v*iv[m*2]; } int main(){ scanf("%d%d%u",&n,&m,&P); if(m>n)m=n; s[0][0]=iv[1]=1; for(int i=2;i<=115;++i)iv[i]=iv[P%i]*(P-P/i); for(int i=1;i<=n;++i){ f0[1][i]=f1[1][i]=s[0][i-1]+s[1][i-1]+s[2][i-1]; gs[1]=f0[1][i]+s[3][i-1]; // printf("[%d:%d]\n",i,gs[1]); for(int j=2;j<=3;++j)gs[j]=gs[j-1]*(gs[1]+(j-1))*iv[j]; for(int j=3;j;--j){ for(int k=n;k>=i;--k){ for(int t=1;t<=j;++t){ int w=k-t*i; if(w>=0)s[j][k]+=gs[t]*s[j-t][w]; } } } } for(int i=2;i<=m;++i){ for(int j=i;j<=n;++j){ for(int k=1;k<j;++k)f0[i][j]+=f0[i-1][j-k]*f0[1][k]; if(i&1){ for(int k=2;k<j;k+=2)f1[i][j]+=f0[i>>1][k>>1]*f0[1][j-k]; }else{ for(int k=1;k<j;++k)f1[i][j]+=f1[i-1][j-k]*f0[1][k]; if(~j&1)f1[i][j]+=f0[i>>1][j>>1]; f1[i][j]=f1[i][j]*iv[2]; } // printf("%d,%d %d %d\n",i,j,f0[i][j],f1[i][j]); } } for(int i=3;i<=m;++i)cal(i,n); printf("%d\n",ans.x); return 0; }

bzoj 2601: [Jsoi2011]同分異構體計數