题意
给N个字符串,找出第一个字符串中最短的一个子串,使得这个子串不在其他所有的字符串中出现。
题解
对于这样一道题,没有现成的工具可以利用,但是既然涉及到了子串的问题,就可以考虑后缀自动机。后缀自动机可以用来找最长公共子串。对于这道题,我们想要利用后缀自动机,就是需要采取一些措施,使得这个问题转化为最长公共子串的问题。
我们可以把其他字符串拼接成一个字符串,需要注意的是要在中间加上一个分割字符,因为如果没有这个字符的话,那么很有可能这个字符串与下一个字符串拼接成一个新的字符串,从而对结果产生影响。
拼接成一个字符串以后,把这个字符串加到后缀自动机上,就可以寻找最长公共子串了,在寻找最长公共子串的过程中,如果发生了失配,那么就意味着存在一段子串,这段子串不在任何一个字符串中存在,而这个字符串的长度就是当前匹配的最长公共子串长度-1。(这个原因是显而易见的,因为匹配失败就意味着不存在这个字串在其他字符串中。)这时候我们就需要比较一下字典序,进行答案的记录。
最后输出记录的位置对应的字符串就可以了。
代码
#include<bits/stdc++.h>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define W(t) while(t)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f
#define eps 1e-10
#define MAXN 3000010
using namespace std;
const int N=250010;
char first[N];
char second[N];
struct Node {
int st,ed;
Node() {}
Node(int st,int ed):st(st),ed(ed) {}
bool operator < (const Node b) const {
int lena=(ed-st+1),lenb=(b.ed-b.st+1);
if(lena==lenb) {
UP(i,0,lena) {
if(first[st+i]!=first[b.st+i]) {
return first[st+i]<first[b.st+i];
}
}
return true;
}
return lena<lenb;
}
};
Node ans;
struct Suffix_Auto {
static const int NODE=N<<1,C=27;
int allc,last,par[NODE],len[NODE],trans[NODE][C];
int newNode() {
int ret=++allc;
MEM(trans[ret],0);
return ret;
}
void init() {
allc=0;
last=newNode();
par[last]=len[last]=0;
}
void extend(int c) {
int p=last,np=newNode();
len[np]=len[last]+1;
for(; p&&!trans[p][c]; p=par[p]) trans[p][c]=np;
if(!p) par[np]=1;
else {
int q=trans[p][c];
if(len[q]==len[p]+1) par[np]=q;
else {
int nq=++allc;
par[nq]=par[q];
len[nq]=len[p]+1;
memcpy(trans[nq],trans[q],C<<2);
par[np]=par[q]=nq;
for(trans[p][c]=nq,p=par[p]; p&&trans[p][c]==q; p=par[p]) trans[p][c]=nq;
}
}
last=np;
}
void update(Node nd) {
if(ans.st==-1) {
ans=nd;
} else if(nd<ans) {
ans=nd;
}
}
void find(const char *st) {
int stlen=strlen(st);
int u=1;
int now=0;
UP(i,0,stlen) {
int x=st[i]-'a';
if(trans[u][x]) {
u=trans[u][x];
now++;
} else {
W(u&&!trans[u][x]) {
u=par[u];
now=len[u];
}
if(u) {
now++;
u=trans[u][x];
} else {
now=0;
u=1;
}
Node newNd=Node(i-now,i);
update(newNd);
}
}
}
};
Suffix_Auto sa;
int main() {
// freopen("d://in.txt","r",stdin);
// freopen("d://out1.txt","w",stdout);
int ks=1;
int t;
scanf("%d",&t);
W(t--) {
sa.init();
int n;
scanf("%d",&n);
UP(i,0,n) {
if(i==0)
scanf("%s",first);
else {
scanf("%s",second);
int len=strlen(second);
UP(i,0,len) sa.extend(second[i]-'a');
sa.extend(26);
}
}
ans.st=-1;
sa.find(first);
printf("Case #%d: ",ks++);
if(ans.st==-1) {
printf("Impossible\n");
} else {
UP(i,ans.st,ans.ed+1) printf("%c",first[i]);
puts("");
}
}
}