SPOJ - PHRASES Relevant Phrases of Annihilation【后缀数组】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/85007521

Time limit 9000 ms
Memory limit 1572864 kB

You are the King of Byteland. Your agents have just intercepted a batch of encrypted enemy messages concerning the date of the planned attack on your island. You immedietaly send for the Bytelandian Cryptographer, but he is currently busy eating popcorn and claims that he may only decrypt the most important part of the text (since the rest would be a waste of his time). You decide to select the fragment of the text which the enemy has strongly emphasised, evidently regarding it as the most important. So, you are looking for a fragment of text which appears in all the messages disjointly at least twice. Since you are not overfond of the cryptographer, try to make this fragment as long as possible.

Input

The first line of input contains a single positive integer t<=10, the number of test cases. t test cases follow. Each test case begins with integer n (n<=10), the number of messages. The next n lines contain the messages, consisting only of between 2 and 10000 characters ‘a’-‘z’, possibly with some additional trailing white space which should be ignored.

Output

For each test case output the length of longest string which appears disjointly at least twice in all of the messages.


题意

给定n个字符串,求这n个字符串的最长公共子串
并满足这个子串在每个字符串中出现至少两次,且不重叠


题目分析

在height上分组的题总是换汤不换药
把n个字符串用不同的特殊字符连接起来求height数组
二分子串长度在height上分组判断
只要有一组其中的sa值满足上面要求即可

即用cnt,mx,mi数组分别记录每个一组内每个后缀在原来每个字符串分别出现多少次以及出现的位置
感觉就是在考码力


#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef double dd;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=200010;
int T,N,n,m;
int a[maxn];
int rak[maxn],sa[maxn],tp[maxn],tax[maxn];
int height[maxn],rem[maxn];
int cnt[13],mx[13],mi[13],judge[13];
char ss[maxn];

void rsort()
{
    for(int i=0;i<=m;++i) tax[i]=0;
    for(int i=1;i<=n;++i) tax[rak[i]]++;
    for(int i=1;i<=m;++i) tax[i]+=tax[i-1];
    for(int i=n;i>=1;--i) sa[tax[rak[tp[i]]]--]=tp[i];
}

void SA()
{
    m=1024;
    for(int i=1;i<=n;++i)
    rak[i]=a[i],tp[i]=i;
    
    rsort();
    for(int k=1;k<=n;k<<=1)
    {
        int p=0;
        for(int i=n-k+1;i<=n;++i) tp[++p]=i;
        for(int i=1;i<=n;++i) if(sa[i]>k) tp[++p]=sa[i]-k;
        
        rsort();
        memcpy(tp,rak,sizeof(rak));
        rak[sa[1]]=p=1;
        for(int i=2;i<=n;++i)
        rak[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?p:++p;
        if(p>=n) break;
        m=p;
    }
}

void getH()
{
    int k=0;
    for(int i=1;i<=n;++i)
    {
        if(k) k--;
        int j=sa[rak[i]-1];
        while(a[i+k]==a[j+k]) k++;
        height[rak[i]]=k;
    }
}

int check(int x)
{
    for(int i=1;i<=11;++i)
    cnt[i]=mx[i]=mi[i]=judge[i]=0;
    
    int sum=0; cnt[rem[sa[1]]]++;
    mx[rem[sa[1]]]=mi[rem[sa[1]]]=sa[1];
    
    for(int i=2;i<=n;++i)
    {
        if(rem[sa[i]]==0) break;
        int id=rem[sa[i]];
        if(height[i]<x)
        {
            for(int j=1;j<=11;++j)
            cnt[j]=mx[j]=mi[j]=judge[j]=0;
    
            sum=0; cnt[id]++;
            mx[id]=mi[id]=sa[i];
        }
        else
        {
            mx[id]=mx[id]==0?sa[i]:max(mx[id],sa[i]);
            mi[id]=mi[id]==0?sa[i]:min(mi[id],sa[i]);
            if(++cnt[id]>=2&&mi[id]+x-1<mx[id]&&judge[id]==0) sum++,judge[id]=1;
            if(sum==N) return 1;
        }
    }
    return 0;
}

int main()
{
    T=read();
    while(T--)
    {
    	N=read(); 
        int sum=0,C=123;
    	for(int i=1;i<=N;++i)
    	{
    		scanf("%s",ss); 
            
            int len=strlen(ss);
    		for(int j=0;j<len;++j)
    		a[sum+j+1]=ss[j],rem[sum+j+1]=i;
    		
    		a[sum+len+1]=C++; 
            sum+=len+1;
        }
        
        n=sum;
        SA(); getH();
        
        int L=0,R=n,mid,ans=0;
        while(L<R)
        {
            mid=L+R>>1;
            if(check(mid)) ans=mid,L=mid+1;
            else R=mid;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/85007521