Unicyclic Graph Counting
计数有多少个有标号环套树,第(i)个点的度数为(D_i),对大质数取模。
(N ≤ 300)。
题解
仓鼠《杂题选讲》。
假定我们已经得到了一个环,大小为(K)。下面我们考虑一种新的Prüfer编码方式,不删除环上的点,只删除树上的点。那么树上点(u)在这个编码中出现次数一定为(D_u − 1),环上点(v)在这个编码中出现次数一定为 (D_v − 2) ,并且序列的最后一个点必须是环上的点。
可以发现,当环的形状确定后,这样的编码方式就和换套树一一对应了。编码总长度为(N − K)。
直接做DP就可以了,记录当前选了多少个点在环上以及序列的最后一个点是否确定,时间复杂度为(O(N^2))。
得特判一个大环的情况。
CO int N=310;
int fac[N],ifac[N];
int d[N],f[N][N][2];
int main(){
int n=read<int>();
fac[0]=1;
for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
ifac[n]=fpow(fac[n],mod-2);
for(int i=n-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
for(int i=1;i<=n;++i) read(d[i]);
f[0][0][0]=1;
for(int i=0;i<n;++i)for(int j=0;j<=i;++j){
f[i+1][j][0]=add(f[i+1][j][0],mul(f[i][j][0],ifac[d[i+1]-1]));
f[i+1][j][1]=add(f[i+1][j][1],mul(f[i][j][1],ifac[d[i+1]-1]));
if(d[i+1]<2) continue;
f[i+1][j+1][0]=add(f[i+1][j+1][0],mul(f[i][j][0],ifac[d[i+1]-2]));
f[i+1][j+1][1]=add(f[i+1][j+1][1],mul(f[i][j][1],ifac[d[i+1]-2]));
if(d[i+1]<3) continue;
f[i+1][j+1][1]=add(f[i+1][j+1][1],mul(f[i][j][0],ifac[d[i+1]-3]));
}
int ans=0;
for(int j=3;j<n;++j)
ans=add(ans,mul(f[n][j][1],mul(fac[n-j-1],mul(fac[j-1],i2))));
if(n>=3) ans=add(ans,mul(f[n][n][0],mul(fac[n-1],i2)));
printf("%d
",ans);
return 0;
}