考试总结 模拟$100$

考试过程

暴力分都拿到了,T1看出了是欧拉路,而且之前也看过书上的板子,但是考场上大脑一片空白,对知识理解不够深入

T2应该多去想想一些比较显然的优化

T3暴力在OJ上T了,但是本机过40分了,可能是厌氧。没看出来为什么,以本机为准吧

 题解

T1「欧拉路」

板子题啊

大概稍总结一下:

欧拉路经的判定:

1.无向图,奇度点有2个起点和终点,其他都是偶度点。若奇度点有0个,则是欧拉回路

2.有向图,除两个特殊点:outd=ind+1的是起点,ind==outd+1的是终点,其余ind==outd,。若都想等的,是欧拉回路

求解:基于这样的性质:路径上的每个点,进去之后,一定会有一条边出来,

dfs一遍,并且用栈记录顺序并且倒序输出即可,每个点枚举所有边的最劣复杂度会是$O(n*m)$

那么用上当前弧优化,就可以避免枚举重复的边

#include<bits/stdc++.h>
#define EXIT {puts("NO");return;}
using namespace std;
inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return f*x;
}
const int maxn=1e5+5;
int T,n,m;
int ind[maxn],outd[maxn];
int n_e=1,ver[maxn<<2],nxt[maxn<<2],head[maxn];
void add(int x,int y){
	ver[++n_e]=y;
	nxt[n_e]=head[x];
	head[x]=n_e;
}
int pvis[maxn];
void pdfs(int x){
	pvis[x]=1;
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(pvis[y])continue;
		pdfs(y);
	}
}
int vis[maxn<<2],sta[maxn<<2],top;
void euler(int x){
	for(int i=head[x];i;){
		if(vis[i]){
			head[x]=i=nxt[i];
		}
		else{
			vis[i]=1;
			if(T==1)vis[i^1]=1;
			head[x]=nxt[i];
			euler(ver[i]);
			sta[++top]=i;
			i=head[x];
		}
	}
}
inline void sol1(){
	for(int i=1;i<=m;++i){
		int x=rd(),y=rd();
		add(x,y),add(y,x);
		++ind[x],++ind[y];
	}
	int S=0,E=0;
	for(int x=1;x<=n;++x){
		if(!(ind[x]&1))continue;
		if(!S) S=x;
		else if(!E) E=x;
		else EXIT
	}
	if(!S)for(int x=1;x<=n;++x)
		if(ind[x]){S=x;break;}
	pdfs(S);
	for(int x=1;x<=n;++x)
		if(!pvis[x]&&ind[x]) EXIT
	puts("YES");
	euler(S);
	for(int i=top;i>=1;--i){
		int nw=sta[i];
		if(nw&1)nw*=-1;
		nw/=2;
		printf("%d ",nw);
	}
}
inline void sol2(){
	for(int i=1;i<=m;++i){
		int x=rd(),y=rd();
		add(x,y);++outd[x],++ind[y];
	}
	int S=0,E=0;
	for(int x=1;x<=n;++x){
		if(ind[x]==outd[x])continue;
		if(ind[x]+1==outd[x]){if(!S)S=x;else EXIT}
		else if(ind[x]==outd[x]+1){if(!E)E=x;else EXIT}
		else EXIT
	}
	
	if(!S)for(int x=1;x<=n;++x)
		if(outd[x]){S=x;break;}
	
	pdfs(S);
	for(int x=1;x<=n;++x)
		if(!pvis[x]&&ind[x]) EXIT
	euler(S);
	puts("YES");
	for(int i=top;i>=1;--i)
		printf("%d ",sta[i]-1);
}
int main(){
	freopen("merge.in","r",stdin);
	freopen("merge.out","w",stdout);
	T=rd(),n=rd(),m=rd();
	if(T==1)sol1();
	else sol2();
}

T2「贪心」「性质题」

可以发现每次的操作过后那一串的点的贡献都变为了0,且其他的点的贡献不变

所以在第二次出现要操作这个点的时候,直接输出上一次的ans

 等会我没写正解

原文地址:https://www.cnblogs.com/casun547/p/11799118.html