LGP3687口胡

神仙题。。。这就是ZJOI吗。。。

首先如果图是非仙人掌,答案一定为 \(0\)。如何判断非仙人掌?删掉所有点双的边,然后数一下点双中的点和被删掉的边。

来考虑仙人掌的情况。仙人掌的环将整个图分成了若干颗树,在环上连边是没有意义的。所以只需要考虑树即可。

考虑意见很许可但是很重要的事情:将一棵树填充成仙人掌时,将不在环上的边强制连接一条重边,变成一个环。

这样一来每条边就在且仅在一个环中了,考虑起来更加方便。

这样一个复杂的东西先考虑 DP。设 \(dp[u]\) 表示 \(u\) 子树内的合法方案数量,且 \(u\) 有一条连向 \(f[u]\) 的还没有拼接起来的边。

很明显一件事,让儿子们xjb匹配,也可以不匹配。然后自身选择一个儿子与其匹配或不匹配。\(u\) 为根节点时没有后面这个匹配。

\(g[n]\) 表示 \(n\) 个节点的菊花图xjb匹配的方案数。转移时考虑 \(n\) 是否要和前面的匹配,有 \(g[n]=g[n-1]+g[n-2]\times(n-1)\)

明显有 \(dp[u]=\prod_{v\in son(u)}dp[v]\times g[|son(u)|+1]\) 什么的东西,反正是可以 \(O(n+m)\) 了。

#include<cstdio>
#include<cctype>
typedef unsigned ui;
const ui M=5e5+5,mod=998244353;
ui T,n,m,cnt,g[M],f[M],d[M],D[M],h[M];ui dfc,dfn[M],low[M];bool vis[M];
char _input[1<<26|1],*_p1=_input;
struct Edge{
	ui v,nx;
}e[M<<2];
inline void Add(const ui&u,const ui&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
	e[++cnt]=(Edge){u,h[v]};h[v]=cnt;
}
inline ui min(const ui&a,const ui&b){
	return a>b?b:a;
}
inline void Tarjan(const ui&u){
	dfn[u]=low[u]=++dfc;d[u]=d[f[u]]+1;
	for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u]){
		if(!dfn[v])f[v]=u,Tarjan(v),low[u]=min(low[u],low[v]);
		else low[u]=min(low[u],dfn[v]);
		if(dfn[u]<low[v])++D[u],++D[v];
	}
}
inline ui read(){
	ui n(0);char s;while(!isdigit(s=*_p1++));while(n=n*10+(s&15),isdigit(s=*_p1++));return n;
}
signed main(){
	fread(_input,1,1<<26,stdin);
	T=read();g[0]=1;g[1]=1;
	for(ui i=2;i<=500000;++i)g[i]=(g[i-1]+(i-1ull)*g[i-2])%mod;
	while(T--){
		ui ans(1);bool typ(false);n=read();m=read();cnt=1;dfc=0;
		for(ui i=1;i<=n;++i)f[i]=d[i]=D[i]=h[i]=dfn[i]=low[i]=0,vis[i]=false;
		for(ui u,v,i=1;i<=m;++i)u=read(),v=read(),Add(u,v);Tarjan(1);
		for(ui i=1;i<=m;++i){
			ui u=e[i<<1].v,v=e[i<<1|1].v;
			if(f[u]==v||f[v]==u)continue;if(d[u]<d[v])u^=v^=u^=v;
			while(d[u]^d[v])typ|=vis[u],vis[u]=true,u=f[u];if(typ)break;
			while(u^v)typ|=vis[u]|vis[v],vis[u]=vis[v]=true,u=f[u],v=f[v];if(typ)break;
		}
		if(typ){
			printf("0\n");continue;
		}
		for(ui u=1;u<=n;++u)ans=1ull*ans*g[D[u]]%mod;printf("%u\n",ans);
	}
}
posted @ 2022-04-07 11:22  Prean  阅读(21)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};