题意:
给出n个串,求一个最短的第一个串的子串使它不在其他的n-1个串中出现,若有多个求字典序最小的。
Limits: • 1 ≤ T ≤ 42. • 2 ≤ N ≤ 50000. • N ≤ S1 + S2 + · · · + SN ≤ 250000. • the sum of Si in all test cases doesn’t exceed 3 × 106 .
Sample Input
3
2
aba
bab
3
qnu
cvbb
bnu
3
a
aa
aaa
Sample Output
Case #1: aba
Case #2: q
Case #3: Impossible
代码:
//这么多串肯定要把他们连接起来(之间用没出现的字符隔开)。后缀数组求出heigh数组,答案要求字典序最小所以后缀数组从前向后找即可,每找到 //一个在第一个串中的i位置时,在该位置向前和向后各找到第一个不在第一个串中的j那么lcp(i,j)一定是i位置和其他不在第一个串中后缀的 //最长的lcp,那么这个lcp+1的长度就一定是在其他串中没有出现过,要求字典序最小所以要向后扩展一位,并且这个长度不能超出第一个串。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN=300000; int t,n,sa[MAXN],he[MAXN],ra[MAXN],xx[MAXN],yy[MAXN],buc[MAXN]; char s[MAXN],ch[MAXN]; int len,len1,m; void get_suf() { int *x=xx,*y=yy; for(int i=0;i<m;i++) buc[i]=0; for(int i=0;i<len;i++) buc[x[i]=s[i]]++; for(int i=1;i<m;i++) buc[i]+=buc[i-1]; for(int i=len-1;i>=0;i--) sa[--buc[x[i]]]=i; for(int k=1;k<=len;k<<=1){ int p=0; for(int i=len-1;i>=len-k;i--) y[p++]=i; for(int i=0;i<len;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) buc[i]=0; for(int i=0;i<len;i++) buc[x[y[i]]]++; for(int i=1;i<m;i++) buc[i]+=buc[i-1]; for(int i=len-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(int i=1;i<len;i++){ if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]) x[sa[i]]=p-1; else x[sa[i]]=p++; } if(p>=len) break; m=p; } for(int i=0;i<len;i++) ra[sa[i]]=i; int k=0; for(int i=0;i<len;i++){ if(ra[i]==0) { he[0]=0;continue; } if(k) k--; int j=sa[ra[i]-1]; while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++; he[ra[i]]=k; } } void solve() { int ans=len,pos=-1; for(int i=0;i<len;i++){ while(i<len&&sa[i]>=len1) i++; if(i>=len) break; int plcp=he[i]; for(int j=i-1;j>=0;j--){ if(sa[j]>=len1) break; plcp=min(plcp,he[j]); } int slcp=he[i+1]; for(int j=i+1;j<=len;j++){ if(sa[j]>=len1) break; slcp=min(slcp,he[j]); } plcp=max(plcp,slcp); if(plcp<len1-sa[i]){ if(plcp+1<ans){ ans=plcp+1; pos=sa[i]; } } } if(pos==-1) puts("Impossible"); else{ for(int i=0;i<ans;i++) printf("%c",s[i+pos]); puts(""); } } int main() { scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d",&n); scanf("%s",s); len=len1=strlen(s); for(int i=2;i<=n;i++){ s[len++]='#'; scanf("%s",s+len); len=strlen(s); } m=200; get_suf(); printf("Case #%d: ",cas); solve(); } return 0; }