UVAL 7902 2016ECfinal F - Mr. Panda and Fantastic Beasts

题意:

给出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;
}

 

posted @ 2017-12-04 13:29  luckilzy  阅读(645)  评论(0编辑  收藏  举报