组合数学 Count QBXT Test Ⅷ T2

题意:求 n n n个带编号的点能组成多少种无向连通图。

考场上直接在想通项,把自己绕进去了,结果就weila。

正解是一个递推,我们设状态 d p [ i ] dp[i] dp[i]表示 i i i个点的无向连通图的种数。

我们用总方案数减去不合法的方案数来求最终的方案数。首先对于一个i个点的图,一共有 2 i ( i − 1 ) 2 2^\frac{i(i-1)}{2} 22i(i1)种不同的图。我们固定 1 1 1号节点,枚举和 1 1 1号点连通的连通块大小 j j j,其他 i − j i-j ij个点一定不和 1 1 1号点连通。

那么与1相连的其它点有 C j − 1 i − 1 C^{i-1}_{j-1} Cj1i1中选法, 1 1 1号节点所在联通块有 d p [ j ] dp[j] dp[j]种连法,不与 1 1 1号节点相连的点有 2 ( i − j ) ∗ ( i − j − 1 ) 2 2^{\frac{(i-j)*(i-j-1)}{2}} 22(ij)(ij1)种连法。所以我们得到递推式: d p [ i ] = 2 i ( i − 1 ) 2 − ∑ j = 1 i − 1 C j − 1 i − 1 ∗ d p [ j ] ∗ 2 ( i − j ) ∗ ( i − j − 1 ) 2 dp[i]=2^\frac{i(i-1)}{2}-\sum_{j=1}^{i-1}C^{i-1}_{j-1}*dp[j]*2^{\frac{(i-j)*(i-j-1)}{2}} dp[i]=22i(i1)j=1i1Cj1i1dp[j]22(ij)(ij1)

n 2 n^2 n2预处理组合数求解即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=998244353;
int n;
ll dp[5005],c[5005][5005],num[5005];
ll ksm(ll q,ll w)
{
	ll h=1;
	while(w)
	{
		if(w&1)
			h=h*q%mod;
		q=q*q%mod;
		w>>=1;
	}
	return h;
}
int main()
{
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	cin>>n;
	for(int i=0;i<=5000;++i)
		c[i][0]=1;
	for(int i=1;i<=5000;++i)
		for(int j=1;j<=i;++j)
			c[i][j]=(c[i-1][j]%mod+c[i-1][j-1]%mod)%mod;
	for(int i=1;i<=n;++i)
		num[i]=ksm(2,(i*(i-1))/2);
	for(int i=1;i<=n;++i)
	{
		dp[i]=num[i];
		ll sum=0;
		for(int j=1;j<=i-1;++j)
		{
			ll tmp=(c[i-1][j-1]*dp[j]%mod*num[i-j])%mod;
			sum=(sum%mod+tmp%mod)%mod;
		}
		dp[i]=(dp[i]+mod-sum)%mod;
	}
	cout<<dp[n];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值