abc226E - Just one

E - Just one

怎么感觉大家都这么懂啊。
结论就是基环森林才有解

证明的话大概是这样

首先不是同一个连通块的话则互不相干,分开讨论即可。

如果一个点的度为1,那么它的出边唯一确定,那么我们可以删去这些点,删去的同时会造成一些新的点度为1,不断扩展即可,同时注意判断无解情况,有点类似于拓扑排序的一个BFS。

那么我们现在假定剩下的点的度都大于等于2,假如不是构成一个环,我们给其中一条边定向\((x->y)\),那么其他与这个点相连的边也确定了方向,必然是指向
\(z->x (z \neq y)\),由于每个点的度大于等于2,则每个点z,也必然存在w,使得\((w->z)\),并且它不会构成一个环,那么点数是无穷大的。

所以必然是一个环的形式,并且是一个简单环。
对于一个环,只看这个环,每个点,一定是一条边近,一条边出,因为进出相等,如果存在一个点两条边都是入,则必然存在一个点会有两条出边。那么我们确定了环上边的方向之后,如果还有别的边,是一定会造成矛盾的,会使这条边上的一点出度大于1。

因此一定是简单环,且方案只有两种。

所以判断下是不是基环森林,然后算联通块个数即可。

#include<cstdio>
#include<algorithm>
#include<set>
#include<queue>
#include<cstring>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++) //
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define A puts("YES")
#define B puts("NO")

using namespace std;
typedef double db;
typedef long long ll;
const int N=2e5+5; 
const ll mo=998244353;
int head[N],to[N*2],nex[N*2],tot,d[N];
bool vis[N],bz[N],del[N];

int n,m,x,y;
queue<int> q;
void add(int x,int y){
	to[++tot]=y; nex[tot]=head[x]; head[x]=tot;
}
void dfs(int x,int y){
	bz[x]=1;
	for (int i=head[x];i;i=nex[i]){
		int v=to[i];
		if (bz[v]) continue;
		dfs(v,x);
	}
}
int main()
{
//	freopen("data.in","r",stdin);
	
	scanf("%d %d",&n,&m);
	fo(i,1,m){
		scanf("%d %d",&x,&y);
		add(x,y); add(y,x);
		d[x]++;
		d[y]++;
	}
	bool flag=1;
	
	fo(i,1,n) {
		if (!d[i]) flag=0;
		if (d[i]==1) q.push(i),vis[i]=1;
	}
	
	if (!flag) {
		puts("0");
		return 0;
	}
	
	while (!q.empty()) {
		x=q.front(); q.pop(); 
		del[x]=1;
		if (!d[x]) {
			flag=0;
			break;
		}
		for (int i=head[x];i;i=nex[i]){
			int v=to[i];
			if (del[v]) continue;
			d[v]--;
			if (d[v]==1) {
				vis[v]=1;
				q.push(v);
			}
		}
	}

	fo(i,1,n) if (!d[i] || d[i]>2) flag=0;
	if (!flag) {
		puts("0");
		return 0;
	}
	
	ll ans=1;
	fo(i,1,n){
		if (!bz[i]) {
			dfs(i,0);
			ans=ans*2ll%mo;
		}
	}
	printf("%lld",ans);

	return 0; 

}

 
    
posted @ 2023-09-13 15:56  gan_coder  阅读(19)  评论(0)    收藏  举报