*题解:CF508D Tanya and Password
解析
貌似是典题。
首先我有一个想法是把每两个字符的组合看成一个点,每个给定字符串 \(s\) 也看成是一个点。每个 \(s\) 向其后缀两个字符连边,其前缀向 \(s\) 连边,那么要求的就是一条经过所有 \(s\) 的路径。直接做不好做,不妨把 \(s\) 变成边,这样就变成求欧拉路径了。
时间复杂度 \(O(n)\)。
代码
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<int,int> pii;
const int N = 2e5 + 5, M = 26 + 26 + 10 + 5, P = 450, mod = (int)1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
string s[N];
int ind[M * M],outd[M * M],now[M * M];
vector<pii> g[M * M];
vector<int> p;
void dfs(int x,int pos){
for(;now[x] < g[x].size();){
int nx = g[x][now[x]].first,id = g[x][now[x]].second;
now[x]++;
dfs(nx,id);
}
p.push_back(pos);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin>>n;
int cnt = 0;
map<pair<char,char>,int> mp;
for(int i=1;i<=n;i++){
cin>>s[i];
if(!mp.count({s[i][0],s[i][1]})){
mp[{s[i][0],s[i][1]}] = ++cnt;
}
if(!mp.count({s[i][1],s[i][2]})){
mp[{s[i][1],s[i][2]}] = ++cnt;
}
g[mp[{s[i][0],s[i][1]}]].push_back({mp[{s[i][1],s[i][2]}],i});
ind[mp[{s[i][1],s[i][2]}]]++;
outd[mp[{s[i][0],s[i][1]}]]++;
}
bool f1 = true;
int cnt1 = 0,cnt2 = 0,pos = 0;
for(int i=1;i<=cnt;i++){
cnt1 += ind[i] == outd[i] + 1;
cnt2 += outd[i] == ind[i] + 1;
if(outd[i] == ind[i] + 1){
pos = i;
}
f1 &= ind[i] == outd[i];
}
if(f1 || (cnt1 == 1 && cnt2 == 1)){
if(f1){
dfs(1,0);
}else{
dfs(pos,0);
}
if(p.size() != n + 1){
cout<<"NO";
return 0;
}
cout<<"YES\n";
string res;
for(int i=p.size() - 2;i>=0;i--){
if(res.empty())
res += s[p[i]];
else
res += s[p[i]][2];
}
cout<<res;
}else{
cout<<"NO";
}
return 0;
}

浙公网安备 33010602011771号