题意:
给定n个串,问其中是否存在一个串,满足其他串都是它的子串。
如果存在这样的串,输出这个串,否则输出No
数据范围:所有串长度不超过1e5
解法:
答案串一定是最长的串,
如果只有一个最长的串,那么将其他串加入AC自动机,然后看是否能匹配满即可。
如果不止一个最长的串,就判断这些串是否相同,如果不同则No,
否则和前面一样,看能否匹配满其他串即可。
ps:
md,原来把AC自动机里面的标记删掉,不能将val[t]改成0,得改成-1,
这题wa爆了,也因此找出了我板子的bug。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
string s[maxm];
char t[maxm];
int L[maxm];
int n;
struct AC{
int a[maxm][26],fail[maxm],val[maxm],tot=0;
void init(){//清空
for(int i=0;i<=tot;i++){
memset(a[i],0,sizeof a[i]);
val[i]=fail[i]=0;
}
tot=0;
}
void add(string s){//建立trie树
int len=s.size();
int node=0;
for(int i=0;i<len;i++){
int v=s[i]-'a';
if(!a[node][v])a[node][v]=++tot;
node=a[node][v];
}
val[node]++;//标记结尾
}
void build(){//构造fail
queue<int>q;
for(int i=0;i<26;i++){
if(a[0][i]){
q.push(a[0][i]);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<26;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}else{
a[x][i]=a[fail[x]][i];
}
}
}
}
int ask(string s){
int len=s.size();
int ans=0;
int node=0;
for(int i=0;i<len;i++){
int v=s[i]-'a';
node=a[node][v];
for(int t=node;t&&val[t]!=-1;t=fail[t]){
ans+=val[t];
val[t]=-1;//匹配过的删掉
}
}
return ans;
}
}ac;
signed main(){
int T;cin>>T;
while(T--){
ac.init();
scanf("%d",&n);
int ma=0;
for(int i=1;i<=n;i++){
scanf("%s",t);
s[i]=(string)t;
L[i]=strlen(t);
ma=max(ma,L[i]);
}
vector<int>maa;
for(int i=1;i<=n;i++){
if(L[i]==ma){
maa.push_back(i);
}
}
int ok=1;
for(int i=1;i<(int)maa.size();i++){
if(s[maa[i]]!=s[maa[0]]){
ok=0;break;
}
}
if(!ok){
puts("No");
}else{
for(int i=1;i<=n;i++){
if(L[i]!=ma){
ac.add(s[i]);
}
}
ac.build();
int ans=ac.ask(s[maa[0]]);
if(ans==n-(int)maa.size()){
strcpy(t,s[maa[0]].c_str());
puts(t);
}else{
puts("No");
}
}
}
return 0;
}