Codeforces Round #445 (Div. 2)-D(拓扑序)

D. Restoration of string
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Output

Print 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.

Examples
input
4
mail
ai
lru
cf
output
cfmailru
input
3
kek
preceq
cheburek
output
NO
Note

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.

题意:给你n个字符串,让你构造出一个字符串,使得给出的n个串在你构成的串中都是出现次数最多的子串。

题解:一眼秒过去感觉不会写,想来想去感觉只能大模拟(也不算大,就是比较烦),这场比赛没打,下来补的这道题,看了一些别人的做法,感觉受益匪浅,仔细想想这道题,也没有想想中复杂,首先我们知道很多情况下答案都是NO。。。并且你构造出的目标串一定是所有字母都只出现一次(不然出现次数最多的一定是单个出现次数最多的字母,而不再是已知串了),其次我们用求拓扑序的方法首先预处理每个字母作为首尾的出度和入度(要知道字符串首的字母出度++,字符串尾的字母入度++),然后我们略微贪心的找当前字母入度为0的开始构造,顺便把一些一定不合法的情况找出来即可。。。

附上补题图(前三题很简单,第四题比赛时不见得能做出来。。。。)



#include<vector>
#include<string>
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int in[30],out[30],flag[30],a[30][30];
string ans;
vector<char>q[30];
void dfs(int x)
{
	flag[x]=0;
	ans+=x+'a';
	for(int i=0;i<q[x].size();i++)
		dfs(q[x][i]);
}
int main(void)
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		string s;
		cin >> s;
		for(int j=0;j<s.size()-1;j++)
		{
			int x=s[j]-'a';
			int y=s[j+1]-'a';
			if(a[x][y]==0)
			{
				in[y]++;
				out[x]++;
				a[x][y]=1;
				flag[x]=flag[y]=1;
				q[x].push_back(y);
			}
		}
		flag[s[0]-'a']=1;
	}
	for(int i=0;i<26;i++)
		if(in[i]>1 || out[i]>1)
		{
			printf("NO\n");
			return 0;
		}
	for(int i=0;i<26;i++)
		if(in[i]==0 && flag[i])
			dfs(i);
	for(int i=0;i<26;i++)
		if(flag[i])
		{
			printf("NO\n");
			return 0;
		}
	cout << ans << endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值