Atcoder Unicyclic Graph Counting

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\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12564091.html
今日推荐