D. Restoration of string 字符串操作

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.



#include <bits/stdc++.h>

using namespace std;

int main()
{
	int n;
	cin >> n;
	vector <int> a(26, -1);
	vector <int> b(26, -1);
	vector <int> cnt(26);
	for (int i=0; i<a.size(); i++){
        cout<<a[i]<<endl;
	}
	for (int i = 0; i < n; i++)
	{
		vector <bool> kek(26);
		string s;
		cin >> s;
		for (auto &c : s)
		{
			c -= 'a';
			cnt[c]++;
			if (kek[c])
			{
				cout << "NO\n";
				return 0;
			}
			else
			{
				kek[c] = true;
			}
		}//判有没有重复字母
		for (int i = 0; i + 1 < (int) s.size(); i++)
		{
			if (a[s[i]] != -1 && a[s[i]] != s[i + 1])
			{
				cout << "NO\n";
				return 0;
			}
			else
			{
				if (b[s[i + 1]] != -1 && b[s[i + 1]] != s[i])
				{
					cout << "NO\n";
					return 0;
				}
				a[s[i]] = s[i + 1];
				b[s[i + 1]] = s[i];
			}
		}
	}//判相同字母出现时的前驱和后缀是否相同
	vector <string> res;
	vector <bool> vis(26);
	for (int i = 0; i < 26; i++)
	{
		if (b[i] == -1 && cnt[i])
		{
			string s = "";
			int x = i;
			while (x != -1)
			{
				vis[x] = 1;
				s += (x + 'a');
				x = a[x];
			}
			res.push_back(s);
		}
	}
	for (int i = 0; i < 26; i++)
	{
		if (!vis[i] && cnt[i])
		{
			cout << "NO\n";
			return 0;
		}
	}//判回文如abc cba, pre[a]=b, pre[b]=a, suf[a]=b, suf[b]=a,但是其实这时-1不是没有遇到前缀,而是表示第一位和第二位,觉得可以用-2 -1分层表示
	sort(res.begin(), res.end(), [] (string a, string b)
	{
		return a + b < b + a;
	});
	for (auto c : res) cout << c;
	cout << '\n';
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值