A substring of some string is called the most frequent, if the number of its occurrences is not less than number of occurrences of any other substring.
You are given a set of strings. A string (not necessarily from this set) is called good if all elements of the set are the most frequent substrings of this string. Restore the non-empty good string with minimum length. If several such strings exist, restore lexicographically minimum string. If there are no good strings, print "NO" (without quotes).
A substring of a string is a contiguous subsequence of letters in the string. For example, "ab", "c", "abc" are substrings of string "abc", while "ac" is not a substring of that string.
The number of occurrences of a substring in a string is the number of starting positions in the string where the substring occurs. These occurrences could overlap.
String a is lexicographically smaller than string b, if a is a prefix of b, or a has a smaller letter at the first position where a and b differ.
Input
The first line contains integer n (1 ≤ n ≤ 105) — the number of strings in the set.
Each of the next n lines contains a non-empty string consisting of lowercase English letters. It is guaranteed that the strings are distinct.
The total length of the strings doesn't exceed 105.
OutputPrint the non-empty good string with minimum length. If several good strings exist, print lexicographically minimum among them. Print "NO" (without quotes) if there are no good strings.
Examples4 mail ai lru cf
cfmailru
3 kek preceq cheburek
NO
One can show that in the first sample only two good strings with minimum length exist: "cfmailru" and "mailrucf". The first string is lexicographically minimum.
题意:构造一个字符串str要求所给的字符串是该串的字串,在str的所有字串中,出现的频率的是最高的,如果有多个答案,输出输出字典序,最小的一个。
思路:构成的字符串所有字母只能出现一次,首先将每个字符串构成一条有方向的链,表示前一个字母可以到达后一个字母
,然后遍历所有的字符串链,将这些链构成的单词连起来就是所求字符串
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<string> using namespace std; const int N = 1e5+10; string a[N],ans; int in[30],out[30]; int vis[30],p[30]; int d[30][30]; int n; int Dfs(int now){ vis[now]=1; ans=ans+(char)(now+'a'); for(int i=0;i<26;i++){ if(d[now][i]){ if(vis[i]) return 0; //被访问过,说明其他链有这个字母,字母出现多次 return Dfs(i); } } return 1; } int main(){ scanf("%d",&n); for(int i=0;i<n;i++){ cin>>a[i]; int len=a[i].length(); for(int j=0;j<len-1;j++){ int x=a[i][j]-'a'; int y=a[i][j+1]-'a'; d[x][y]=1;//建一条从x->y的有向边 } if(len==1) p[a[i][0]-'a']=1; //单个点 } for(int i=0;i<26;i++) if(d[i][i]){ //判断自环,说明改字母出现了多次 printf("NO\n"); return 0; } for(int i=0;i<26;i++) for(int j=0;j<26;j++) if(d[i][j]) in[j]++,out[i]++; for(int i=0;i<26;i++) if(in[i]>1||out[i]>1){ printf("NO\n"); return 0; } ans=""; for(int i=0;i<26;i++){ //字母从小到大加,保证新字符串的字典序最小 if(out[i]!=0&&in[i]==0){ //从某条字符串链,起点开始,入度为0,出度为1 if(!Dfs(i)){ printf("NO\n"); return 0; } } if(p[i]&&in[i]==0&&out[i]==0) ans=ans+(char)(i+'a'); //只有一个字母 } for(int i=0;i<26;i++){ if(out[i]!=0||in[i]!=0){ if(!vis[i]){ //在DFS中没有被标记,说明构成了环 printf("NO\n"); return 0; } } } cout<<ans<<endl; return 0; }