ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P5333-[JSOI2019]神经网络【dp,容斥】

2022-05-31 20:35:32  阅读:123  来源: 互联网

标签:P5333 JSOI2019 ll 路径 容斥 一棵树 每棵 include


正题

题目链接:https://www.luogu.com.cn/problem/P5333


题目大意

给出\(n\)棵树,第\(i\)棵树有\(k_i\)个点,每棵树上的每个点和其它树上的所有点都有连边。

求这棵树有多少条哈密顿回路。

答案对\(998244353\)取模。

\(\sum_{i=1}^nk_i\leq 5000\)


解题思路

我们把每棵树分成若干条路径,那么这个哈密顿回路肯定是这些路径拼起来,并且相邻的路径不能来自于同一棵树。

那么对于每棵树我们先算出一个\(g_i\)表示将这棵树分成\(i\)条路径的方案数。

至于相邻的路径不能来自于同一棵树的限制我们考虑容斥,我们硬将一棵树上\(i\)条路径相邻的放那么容斥系数就是\((-1)^i\)。

然后背包出总共\(i\)条路径的方案,像可重排一样在前面一棵树上\(j\)条路径的就乘上\(\frac1{j!}\),最后乘上\(i!\)就好了。

然后为了防止算重我们固定从\(1\)出发,那么处理第一棵树的时候我们就默认有一个放最前面,然后再减去头尾都来自第\(1\)棵树的方案就好了。

时间复杂度:\(O((\sum k_i)^2)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=5100,P=998244353;
struct node{
	ll to,next;
}a[N<<1];
ll n,m,sum,tot,ls[N],g[N],h[N];
ll siz[N],f[N][N][3],tmp[N][3];
ll fac[N],inv[N];
void addl(ll x,ll y){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;return;
}
void dfs(ll x,ll fa){
	siz[x]=1;f[x][0][2]=1;
	for(ll i=ls[x];i;i=a[i].next){
		ll y=a[i].to;
		if(y==fa)continue;
		dfs(y,x);
		for(ll j=0;j<=siz[x];j++)
			for(ll k=0;k<=siz[y];k++){
				(tmp[j+k][2]+=f[x][j][2]*f[y][k][0]%P)%=P;
				(tmp[j+k][1]+=f[x][j][2]*f[y][k][1]%P)%=P;
				(tmp[j+k][1]+=f[x][j][1]*f[y][k][0]%P)%=P;
				(tmp[j+k][0]+=f[x][j][0]*f[y][k][0]%P)%=P;
				(tmp[j+k+1][0]+=f[x][j][1]*f[y][k][1]*2ll%P)%=P;
			}
		siz[x]+=siz[y];
		for(ll j=0;j<=siz[x];j++)
			for(ll k=0;k<3;k++)
				f[x][j][k]=tmp[j][k],tmp[j][k]=0;
	}
	for(ll i=0;i<=siz[x];i++){
		(f[x][i+1][0]+=f[x][i][1]*2ll)%=P;
		(f[x][i+1][0]+=f[x][i][2])%=P;
		(f[x][i][1]+=f[x][i][2])%=P;
	}
	return;
}
ll C(ll n,ll m)
{return fac[n]*inv[m]%P*inv[n-m]%P;}
signed main()
{
	fac[0]=inv[0]=inv[1]=h[0]=1;
	for(ll i=2;i<N;i++)inv[i]=P-inv[P%i]*(P/i)%P;
	for(ll i=1;i<N;i++)fac[i]=fac[i-1]*i%P,inv[i]=inv[i-1]*inv[i]%P;
	scanf("%lld",&m);
	for(ll p=1;p<=m;p++){
		scanf("%lld",&n);
		for(ll i=1;i<=n;i++)ls[i]=0;tot=0;
		for(ll i=1,x,y;i<n;i++){
			scanf("%lld%lld",&x,&y);
			addl(x,y);addl(y,x);
		}
		dfs(1,0);sum+=n;
		for(ll i=0;i<=n;i++)g[i]=0;
		if(p!=1){
			for(ll i=1;i<=n;i++)
				for(ll j=i;j<=n;j++)
					(g[i]+=f[1][j][0]*fac[j]%P*C(j-1,i-1)%P*(((j-i)&1)?(P-1):1)%P)%=P;
		}
		else{
			for(ll i=1;i<=n;i++)
				for(ll j=i;j<=n;j++)
					(g[i-1]+=f[1][j][0]*fac[j-1]%P*C(j-1,i-1)%P*(((j-i)&1)?(P-1):1)%P)%=P;
			for(ll i=2;i<=n;i++)
				for(ll j=i;j<=n;j++)
					(g[i-2]+=f[1][j][0]*fac[j-1]%P*C(j-1,i-1)%P*(((j-i)&1)?1:(P-1))%P)%=P;
		}
		for(ll i=1;i<=n;i++)g[i]=g[i]*inv[i]%P;
		for(ll j=sum;j>=0;j--){
			ll tmp=0;
			for(ll i=0;i<=min(n,j);i++)
				(tmp+=h[j-i]*g[i]%P)%=P;
			h[j]=tmp;
		}
		for(ll i=1;i<=n;i++)
			for(ll j=0;j<=siz[i];j++)
				for(ll k=0;k<3;k++)f[i][j][k]=0;
	}
	ll ans=0;
	for(ll i=0;i<=sum;i++)
		(ans+=h[i]*fac[i]%P)%=P;
	printf("%lld\n",ans);
	return 0;
}

标签:P5333,JSOI2019,ll,路径,容斥,一棵树,每棵,include
来源: https://www.cnblogs.com/QuantAsk/p/16332093.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有