Pretestが甘いこともあり、しょうもないミスをしたままSubmitしてしまった。
http://codeforces.com/contest/889/problem/B
問題
N個の文字列T[i]が与えられる。
文字列Sに対し、別の文字列が良い文字列であるとは、その文字列がS中に部分列として登場する回数が最多(同着の他の文字列があってもよい)ことである。
入力の文字列群に対し、それらが良い文字列となるような文字列Sとしてあり得るもののうち、辞書順最小のものを求めよ。
解法
同じアルファベットが2回出てしまうと、良い文字列は2回以上部分列として登場しなければならないため、同じアルファベットが2回登場することはない。
ここで各文字列T[i]について考える。
T[i][j]とT[i][j+1]は元の文字列S中で連続して登場しなければならない、という関係を覚えておこう。
アルファベットの各文字を頂点としたグラフにおいて、この関係を有向辺として張ろう。
すると、このグラフは閉路を持たず、各入次数・出次数は1以下でなければならない。
逆に各入次数・出次数が1以下なら、このグラフはいくつかの有向パスによって、各頂点を1回ずつ通り、かつ辺も1回ずつ通るよう分解できる。
元のT中に登場するアルファベットのうち、パスの始点となるもののアルファベット昇順で、パスの要素を並べていけばよい。
int N; int cand[26]; set<int> from[26],to[26]; string S; void solve() { int i,j,k,l,r,x,y; string s; cin>>N; FOR(i,N) { cin>>S; FORR(c,S) { c-='a'; cand[c]=1; } FOR(j,S.size()-1) { from[S[j+1]].insert(S[j]); to[S[j]].insert(S[j+1]); } } FOR(i,26) { if(from[i].size()>1 || to[i].size()>1) return _P("NO\n"); } string R; FOR(i,26) if(cand[i]==1 && from[i].size()==0) { int cur=i; while(1) { R+=(char)('a'+cur); if(to[cur].empty()) break; cur=*to[cur].begin(); } } if(R.size()!=count(cand,cand+26,1)) R="NO"; cout<<R<<endl; }
まとめ
なぜしょうもないミスをしたのか…。