Problem Description
Here you have a set of strings. A dominator is a string of the set dominating all strings else. The string S is dominated by T if S is a substring of T.
Input
The input contains several test cases and the first line provides the total number of cases.
For each test case, the first line contains an integer N indicating the size of the set.
Each of the following N lines describes a string of the set in lowercase.
The total length of strings in each case has the limit of 100000.
The limit is 30MB for the input file.
Output
For each test case, output a dominator if exist, or No if not.
Sample Input
3
10
you
better
worse
richer
poorer
sickness
health
death
faithfulness
youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness
5
abc
cde
abcde
abcde
bcde
3
aaaaa
aaaab
aaaac
Sample Output
youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness
abcde
No
当时想到的是AC自动机,算一下时间复杂度,AC自动机建树100000,查询100000
时间是够的,这里先找最长的字符串长len,判断一些是否有多个长度为len不同的字符串,然后建数,跑一次AC自动机就ok
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair<int,int>
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef vector<int> vi;
typedef long long ll;
typedef unsigned long long ull;
inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
const int N = 1e5+1;
const int M = 26;
class Trie
{
public:
//next数组存储树
//fail数组存储下一个要匹配的节点号
//end数组主要是用来标记一个模式串结尾
int next[N][M],fail[N],end[N];
int root,L;
int newnode()
{
for(int i = 0;i < M;i++)//每一个节点对应0-128中的任意一个。
next[L][i] = -1;
end[L++] = 0;//表示下面没有节点 初始化,如果是记录次数,就赋0 还可以赋任意的数,
return L-1;
}
void init()
{
L = 0;
root = newnode();
}
void insert(const char s[])
{
int len = strlen(s);
int now = root;
for(int i = 0;i < len;i++)
{
int k =s[i]-'a';
if(next[now][k] == -1)
next[now][k] = newnode();
now=next[now][k];
}
// end[now]=id;//记录当前匹配单词的节点
end[now]++;//也可以用匹配单词结束后来记录次数
}
//BFS求fail
void build()
{
queue<int>Q;
fail[root] = root;
//初始化root及其子节点
for(int i = 0;i < M;i++)
if(next[root][i] == -1)
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while(!Q.empty())
{
int now = Q.front();
Q.pop();
//遍历节点
for(int i = 0;i < M;i++)
if(next[now][i] == -1)
//不需要失配函数,对所有转移一视同仁
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
int query(const char buf[])
{
int ans=0;
int len = strlen(buf);
int now = root;
bool flag = false;
for(int i = 0;i < len;i++)
{
int k =buf[i]-'a';
now = next[now][k];
int temp = now;
//其会匹配多个模式串
while(temp != root)
{
ans+=end[temp];
end[temp] = 0;
temp = fail[temp];
}
}
return ans;
}
};
char buf[100005];
Trie ac;
int T;
vector<pair<string,int>> ss;
set<string> st;
string s;
int main()
{
// freopen("data.txt","r",stdin);
int n,m;
scanf("%d",&T);
for(int k=0;k<T;k++)
{
ss.clear();
st.clear();
int len = 0,maxl = 0;
scanf("%d",&n);
for(int i = 0;i <n;i++)
{
scanf("%s",buf);
len = strlen(buf);
s = buf;
ss.push_back(make_pair(s,len));
maxl = max(len,maxl);
}
for(int i=0;i<n;i++)
{
if(ss[i].second==maxl)
{
st.insert(ss[i].first);
}
if(st.size()>1)
{
printf("No\n");
break;
}
}
if(st.size()>1)
{
continue;
}
ac.init();
for(int i=0;i<n;i++)
{
ac.insert(ss[i].first.c_str() );
}
ac.build();
s = *st.begin();
// cout <<ac.query(s.c_str())<<endl;
if(ac.query(s.c_str())==n)
{
printf("%s\n",s.c_str());
}
else
{
printf("No\n");
}
}
return 0;
}