【abc180F】Unbranched

题意

问有多少个满足以下条件且有 \(n\) 个点 \(m\) 条边的图:

  1. 没有自环
  2. 每个点的度最大为 \(2\)
  3. 最大的连通块大小恰好为 \(L\)

思路

因为要求最大的连通块恰好为 \(L\),发现比较恶心。
不妨定义 \(F(L)\) 表示最大为 \(L\) 的,则 \(F(L)-F(L-1)\) 就是答案。
首先分析:由于每个点的度最大为 \(2\),所以可以判断每个联通块要么是链,要么是环。
所以可以设计状态 \(f_{i,j}\) 表示有 \(i\) 个点,\(j\) 条边的满足条件的图的个数。

  • 对于长为 \(i\) 的链,有 \(\frac{i!}{2}\) 种方案。
  • 对于长为 \(i\) 的环,有 \(\frac{(i-1)!}{2}\) 种方案(原排列)。

除以 \(2\) 是为了去重。
那如何解决连通块之间的去重问题?可以采用钦定最小值的方法,则我们在 \(n\) 个点里面选 \(i\) 个点出来组成一个连通块的方案数为 \(\binom{n-1}{i-1}\)\(-1\) 是因为钦定了最小值。
则有转移式:

\[f_{i,j} = f_{i-t,j-t+1} * \binom{n-i+t-1}{t-1} \frac{t!}{2} \]

\[f_{i,j} = f_{i-t,j-t} * \binom{n-i+t-1}{t-1} \frac{(t-1)!}{2} \]

大小为 \(1\) 的链和大小为 \(2\) 的环不用除以 \(2\),因为不重。

#include<bits/stdc++.h>
#define ll long long

using namespace std;

const ll N = 305,mod = 1e9+7,inv = 500000004;

int n,m,L;
ll f[N][N];
ll C[N][N],fac[N];

void init() {
	C[0][0]=1,fac[0]=1;
	for(int i=1;i<=300;i++)
		fac[i]=fac[i-1]*i%mod;
	
	for(int i=1;i<=300;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
}

void add(ll &x,ll y){
	(x+=y)%=mod;
}

ll DP(ll lim){
	memset(f,0,sizeof(f));
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int t=1;t<=min(lim,(ll)i);t++){
				if(t>1 && j>=t)add(f[i][j],1ll*f[i-t][j-t]%mod*C[n-i+t-1][t-1]%mod*fac[t-1]%mod*(t==2 ? 1 : inv)%mod);
				if(j>=t-1)add(f[i][j],1ll*f[i-t][j-t+1]%mod*C[n-i+t-1][t-1]%mod*fac[t]%mod*(t==1 ? 1 : inv)%mod);
			}
		}
	}
	return f[n][m];
}
int main() {
	cin>>n>>m>>L;
	init();
	cout<<(DP(L)-DP(L-1)+mod)%mod;
	return 0;
}
posted @ 2025-09-17 21:23  Harvey-zhuhy  阅读(8)  评论(0)    收藏  举报