Gym 102538H Horrible Cycles

题目传送门

我们把点先按照合理的顺序加入,使得每个左部点加入时都恰好与所有右部点相连。

然后设 \(f_{i,j}\) 表示前 \(i\) 个点,一共有 \(j\) 条链的方案数。这里的链指的是一串相连的点(孤立点也算一条链)。

接下来我们对加入的点进行分类讨论:

  • 加入的是右部点。此时这个点没有与任何点连边,故如果选则多了一条链,当然也可以不选。转移方程:\(f_{i,j}\leftarrow f_{i-1,j}+f_{i-1,j-1}\)

  • 加入的是左部点。此时这个点与所有右部点都有连边,对于状态 \(f_{i,j}\) 如果选这个点的话,相当于合并两条链,方案数为 \(\binom {j}{2}\times 2\times 2=j\times (j+1)\times 2\)。但是注意到这个东西在孤立点上有问题。我们再分类讨论一下连接的两部分都是什么:

    • 两条链:我们认为这样少算了一次。

    • 一孤立点一链:我们认为这样正好。

    • 两个点:我们认为这样多算了一次。

设一共有 \(j+1\) 条链和孤立点,其中有孤立点 \(k\) 个,不难发现总方案数为 \(k\times (k-1)+2\times k\times (j+1-k)+(j+1-k)\times (j-k)=(j+1)\times j\)

但是这样我们通过手玩一下会发现,最后会多算一次,所以答案还要除以 \(2\)

最后,我们统计答案是在即将加入一个左部点时进行的,但是这样如果右边只有一个孤立点会被多算,所以还要减掉 \(\sum a_i\)

AC code:

#include<bits/stdc++.h>
#define int long long
#define N 5005
#define mod 998244353
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
int T=1,n,a[N],f[N];
void solve(int cs){
	cin>>n;
	int res=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		(res+=mod-a[i])%=mod;
	}
	sort(a+1,a+n+1);
	f[0]=1;
	for(int i=1;i<=n;i++){
		int t=a[i]-a[i-1];
		while(t--){
			for(int j=n;j;j--){
				(f[j]+=f[j-1])%=mod;
			}
		}
		(res+=f[1])%=mod;
		for(int j=1;j<=n;j++){
			(f[j]+=f[j+1]*(j+1)%mod*j%mod)%=mod;
		}
	}
	if(res&1)res+=mod;
	res>>=1;
	cout<<res<<'\n';
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	cin>>T;
//	init();
	for(int cs=1;cs<=T;cs++){
		solve(cs);
	}
	return 0;
}
posted @ 2025-03-25 20:27  zxh923  阅读(27)  评论(0)    收藏  举报