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

1|0正题

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


1|1题目大意

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

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

答案对998244353取模。

i=1nki5000


1|2解题思路

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

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

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

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

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

时间复杂度:O((ki)2)


1|3code

#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; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16332093.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示