CF508D Solution
题解
对于三元组\(a\),从二元组\(\overline{a_1a_2}\)到二元组\(\overline{a_2a_3}\)连一条有向边。二元组转换为\(62\)进制的数保存,求全图的欧拉通路即可。此外,若直接使用邻接矩阵或邻接表存边,会因为访问大量已经过的边而超时(毕竟有重边,单个点会被搜索多次),时间复杂度最坏为\(O(nm)\)(\(n,m\)分别为点、边数,\(1\le m\le 10^5,1\le 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\n%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;
}