AHOI/HNOI2018毒瘤


思路历程

1-4 20pts \(2^nn\)枚举

5-6 10pts \(f[i][0/1]\)

7-8 10pts 基环树 总数-强制选多出来的那条边的两点

9-14 30pts \(2^{m-n+1}\)枚举多出来的边容斥

100pts 虚树

SOL

对多出来的边的点建立虚树

其实不用容斥,每次强制每条边上的点是否选(都是合法状态),加起来就是ans

\(k[v][0/1][0/1]\)表示v转移到虚树上的fa,v、fa选不选是转移系数,预处理出来就OK(简单的树形DP)

注意本题的大多数DP合并两个子节点是\(\prod\)

时间复杂度\(O(s2^s),s=n-m+1\)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4,mod=998244353;
vector<int>e[N],t[N];
#define pb push_back
#define ll long long
int n,m,tim,cu,ans;
int mark[N],dfn[N],vis[N],uu[40],vv[40],sz[N];
int g[N][2],k[N][2][2],h[N][2][2],f[N][2],li[N][2];
void xsdfs(int x,int fa){
	dfn[x]=++tim;
	for(auto v:e[x]){
		if(v==fa)continue;
		if(!dfn[v]){
			xsdfs(v,x);
			sz[x]+=sz[v];
			continue;
		}
		mark[x]=1;
		if(dfn[x]<dfn[v]){
			uu[++cu]=x;
			vv[cu]=v;
		}
	}
	mark[x]|=(sz[x]>=2);
	sz[x]=sz[x]||mark[x];
}
int predfs(int x){
	vis[x]=1;
	g[x][0]=g[x][1]=1;
	int las,pos=0;
	for(auto v:e[x]){
		if(vis[v])continue;
		las=predfs(v);
		if(!las){
			g[x][1]=(ll)g[x][1]*g[v][0]%mod;
			g[x][0]=(ll)g[x][0]*(g[v][0]+g[v][1])%mod;
		}
		else if(mark[x]){
			t[x].pb(las);
			k[las][0][0]=(h[v][1][0]+h[v][0][0])%mod;
			k[las][0][1]=(h[v][1][1]+h[v][0][1])%mod;
			k[las][1][0]=h[v][0][0];
			k[las][1][1]=h[v][0][1];
		}
		else{
			h[x][0][0]=(h[v][1][0]+h[v][0][0])%mod;
			h[x][0][1]=(h[v][1][1]+h[v][0][1])%mod;
			h[x][1][0]=h[v][0][0];
			h[x][1][1]=h[v][0][1];
			pos=las;
		}
	}
	if(mark[x]){
		h[x][0][0]=h[x][1][1]=1;
		h[x][0][1]=h[x][1][0]=0;
		pos=x;
	}
	else{
		h[x][0][0]=(ll)h[x][0][0]*g[x][0]%mod;
		h[x][0][1]=(ll)h[x][0][1]*g[x][0]%mod;
		h[x][1][0]=(ll)h[x][1][0]*g[x][1]%mod;
		h[x][1][1]=(ll)h[x][1][1]*g[x][1]%mod;
	}
	return pos;
}
void dpdfs(int x){
	f[x][0]=li[x][1]?0:g[x][0];
	f[x][1]=li[x][0]?0:g[x][1];
	for(auto v:t[x]){
		dpdfs(v);
		f[x][0]=((ll)f[v][0]*k[v][0][0]+(ll)f[v][1]*k[v][0][1])%mod*f[x][0]%mod;
		f[x][1]=((ll)f[v][0]*k[v][1][0]+(ll)f[v][1]*k[v][1][1])%mod*f[x][1]%mod;
	}
}
int main(){
	n=read();m=read();
	for(int i=1,u,v;i<=m;i++){
		u=read();v=read();
		e[u].pb(v);e[v].pb(u);
	} 
	xsdfs(1,0);mark[1]=1;
	predfs(1);
	for(int s=0,S=(1<<m-n+1);s<S;s++){
		for(int i=1;i<=m-n+1;i++)
			if((s>>i-1)&1)li[uu[i]][1]=li[vv[i]][0]=1;
			else li[uu[i]][0]=1;
		dpdfs(1);
		ans=((ll)ans+f[1][1]+f[1][0])%mod;
		for(int i=1;i<=m-n+1;i++)
			if((s>>i-1)&1)li[uu[i]][1]=li[vv[i]][0]=0;
			else li[uu[i]][0]=0;
	}
	cout<<ans; 
	return (0-0);
}
posted @ 2020-03-31 12:39  starusc  阅读(122)  评论(0)    收藏  举报