CF508D Solution

题目链接

题解

对于三元组(a),从二元组(overline{a_1a_2})到二元组(overline{a_2a_3})连一条有向边。二元组转换为(62)进制的数保存,求全图的欧拉通路即可。此外,若直接使用邻接矩阵或邻接表存边,会因为访问大量已经过的边而超时(毕竟有重边,单个点会被搜索多次),时间复杂度最坏为(O(nm))(n,m)分别为点、边数,(1le mle 10^5,1le n<62^2))。因此使用vector(特殊处理的邻接表应该亦可)储存每个节点的出边,从上一次访问到的下标(cnt)开始遍历即可,时间复杂度为(O(m))

代码

#include<bits/stdc++.h>
using namespace std;
const int M=2e5+10,N=4000;
int in[N],out[N],ans[M],tot,cnt[N]; 
char a[M][5],o[N][2];
vector<int> e[N];
inline int read()
{
	int s=0,w=1; char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') w=-1; ch=getchar();}
	while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
int id(char x)
{
	if(x>='0' && x<='9') return x-'0';
	if(x>='A' && x<='Z') return x-'A'+10;
	return x-'a'+36;
}
void dfs(int x)
{
	int sz=e[x].size();
	while(cnt[x]<sz) dfs(e[x][cnt[x]++]);
	ans[++tot]=x;
}
int main()
{
	int n=read(),x,y;
	for(int i=1;i<=n;i++) 
	{
		scanf("%s",a[i]+1); 
		x=id(a[i][1])*62+id(a[i][2]),y=id(a[i][2])*62+id(a[i][3]);
		o[x][0]=a[i][1],o[x][1]=a[i][2];
		o[y][0]=a[i][2],o[y][1]=a[i][3];
		e[x].push_back(y);
		in[y]++,out[x]++;
	}
	int st=0,ed=0;
	for(int i=1;i<N;i++)
	{
		if(abs(in[i]-out[i])>=2) {printf("NO"); return 0;}
		if(in[i]-out[i]==1)
		{
			if(ed) {printf("NO"); return 0;}
			ed=i;
		}
		if(out[i]-in[i]==1)
		{
			if(st) {printf("NO"); return 0;}
			st=i;
		}
	}
	for(int i=1;i<N && (!st);i++)
		if(in[i] || out[i]) st=i;
	dfs(st);
	if(tot!=n+1) {printf("NO"); return 0;}
	printf("YES
%c%c",o[ans[tot]][0],o[ans[tot]][1]);
	for(int i=tot-1;i>=1;i--) printf("%c",o[ans[i]][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14839852.html