题意:两个图AB同构:把A的顶点重新编号后与B一模一样。求n个顶点的图一共有多少个?(同构的算一种)
思路:边有n*(n-1)/2,这些边可以有可以没有,所以等同于边的颜色有两种。然后将n划分成循环节的和,n=L1+L2+……+Lm。现在需要把点置换映射到边置换。两个边在一个点循环节(大小L)时边置换循环节为L/2,否则为Gcd(L1,L2)。然后就是计算(L1,L2,……,Lm)这种划分的个数,设m个循环有t种数字,每种数字个数p1,p2,……,pt,那么划分个数为:n!/(L1*L2……*Lm*p1!*……*pt!)。
const int mod=997; int p[N]; int n; int f[N][2],cnt; void init() { p[0]=1; int i; for(i=1;i<N;i++) p[i]=p[i-1]*i%mod; } int ans; void cal() { i64 x=0,i,j; FOR0(i,cnt) { x+=f[i][0]/2*f[i][1]+(f[i][1]-1)*f[i][1]/2*f[i][0]; for(j=i+1;j<cnt;j++) x+=f[i][1]*f[j][1]*Gcd(f[i][0],f[j][0]); } i64 pp=1; FOR0(i,cnt) pp=pp*myPow(f[i][0],f[i][1],mod)%mod*p[f[i][1]]%mod; pp=p[n]*gcdReverse(pp,mod)%mod; ans+=myPow(2,x,mod)*pp%mod; ans%=mod; } void DFS(int t,int re) { if(re==0) { cal(); return; } if(t>re) return; DFS(t+1,re); int i; for(i=1;i*t<=re;i++) { f[cnt][0]=t; f[cnt++][1]=i; DFS(t+1,re-i*t); cnt--; } } int main() { init(); RD(n); DFS(1,n); ans=ans*gcdReverse(p[n],mod)%mod; PR(ans); }