CF508D
题解
考虑把每一个串的前两位和后两位分别看成一个点(字符串哈希),从前向后连边,问题转化成求所建图的欧拉路径。
对于有向图的欧拉路径,常规操作请移步P7771 【模板】欧拉路径。
对于本题而言,有一点易错的细节:
- 有自环,重边,所以点数我开到 \(256\times 256\),但边数还是 \(2\times 10^5\)。
- 图可能不连通,所以加上一条判断,如果栈内元素是 \(n+1\) 个才有解。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define FCC fclose(stdin),fclose(stdout)
const int INF = 0x3f3f3f3f,base=256,N = 257*257;
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n;
int head[N],ecnt=-1;
int ind[N],oud[N];
inline void init_edge(){memset(head,-1,sizeof(head)),ecnt=-1;}
struct edge
{
int nxt,to;
}a[200005];
bool vis[N];
inline void add_edge(int x,int y)
{
a[++ecnt]=(edge){head[x],y};
head[x]=ecnt;
ind[y]++,oud[x]++;
vis[x]=1,vis[y]=1;
}
int S,T,stk[N],top;
char str[N][3];
void dfs(int u)
{
for(int i=head[u];~i;i=head[u])
{
int v=a[i].to;
head[u]=a[i].nxt;//链前的删边操作
dfs(v);
}
stk[++top]=u;
}
int main()
{
init_edge();
n=read();
for(int i=1;i<=n;i++)
{
char s[6];
scanf("%s",s+1);
int u=(s[1]-'0'+1)*base+s[2]-'0'+1;
int v=(s[2]-'0'+1)*base+s[3]-'0'+1;
add_edge(u,v);
str[u][1]=s[1],str[u][2]=s[2];
str[v][1]=s[2],str[v][2]=s[3];
//cout<<str[u]<<'\n';
//printf("%d->%d\n",u,v);
S=u;
}
int cnt=0;
for(int i=0;i<=256*256;i++)
{
if(!vis[i]) continue;
if(oud[i]-ind[i]==1) S=i;
if(oud[i]-ind[i]==-1) T=i;
if(abs(oud[i]-ind[i])>1) return puts("NO"),0;
cnt+=(oud[i]!=ind[i]);
}
if(cnt!=2&&cnt) return puts("NO"),0;
dfs(S);
//printf("S=%d,top=%d\n",S,top);
if(top+1!=n+2) return puts("NO"),0;
bool fir=0;
puts("YES");
while(top)
{
if(!fir) printf("%c",str[stk[top]][1]),fir=1;
printf("%c",str[stk[top]][2]),top--;
}
return 0;
}