POJ-1743 Musical Theme(后缀数组)

Posted 真正的强者,从不埋怨黎明前的黑暗!!!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ-1743 Musical Theme(后缀数组)相关的知识,希望对你有一定的参考价值。

题目大意:给一个整数序列,找出最长的连续变化相同的、至少出现两次并且不相重叠一个子序列。

题目分析:二分枚举长度进行判定。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
# define mid (l+(r-l)/2)

const int N=20000;

int SA[N+5],height[N+5];
int *rk,*tSA;
int n,a[N+5],cnt[N+5];

bool same(int i,int j,int k)
{
    if(tSA[i]!=tSA[j]) return false;
    if(i+k>=n&&j+k>=n) return true;
    if(i+k>=n&&j+k<n) return false;
    if(i+k<n&&j+k>=n) return false;
    return tSA[i+k]==tSA[j+k];
}

void buildSA()
{
    int m=180;
    for(int i=0;i<m;++i) cnt[i]=0;
    for(int i=0;i<n;++i) ++cnt[rk[i]=a[i]];
    for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
    for(int i=n-1;i>=0;--i) SA[--cnt[rk[i]]]=i;
	
    for(int k=1;k<n;k<<=1){
        int p=0;
        for(int i=n-k;i<n;++i) tSA[p++]=i;
        for(int i=0;i<n;++i) if(SA[i]>=k) tSA[p++]=SA[i]-k;

        for(int i=0;i<m;++i) cnt[i]=0;
        for(int i=0;i<n;++i) ++cnt[rk[tSA[i]]];
        for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
        for(int i=n-1;i>=0;--i) SA[--cnt[rk[tSA[i]]]]=tSA[i];

        swap(rk,tSA);
        p=1;
        rk[SA[0]]=0;
        for(int i=1;i<n;++i){
            if(same(SA[i],SA[i-1],k)) rk[SA[i]]=p-1;
            else rk[SA[i]]=p++;
        }
        if(p>=n) break;
        m=p;
    }
}

void getHeight()
{
    for(int i=0;i<n;++i) rk[SA[i]]=i;
    int k=0;
    height[0]=0;
    for(int i=0;i<n;++i){
		if(rk[i]==0) k=0;
		else{
			if(k) --k;
			int j=SA[rk[i]-1];
			while(i+k<n&&j+k<n&&a[i+k]==a[j+k]) ++k;
			height[rk[i]]=k;
		}
    }
}

bool ok(int x)
{
	int maxn=SA[0],minn=SA[0];
	for(int i=1;i<n;++i){
		if(minn+x<maxn) return true;
		if(height[i]>=x){
			maxn=max(maxn,SA[i]);
			minn=min(minn,SA[i]);
		}else{
			maxn=minn=SA[i];
		}
	}
	return minn+x<maxn;
}

void init()
{
    rk=new int[n+5];
    tSA=new int[n+5];
}

void destroy()
{
    delete []rk;
    delete []tSA;
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        init();
        for(int i=0;i<n;++i){
            scanf("%d",a+i);
            --a[i];
        }
		--n;
		int temp=a[0];
		for(int i=0;i<n;++i){
			a[i]=a[i+1]-temp+87;
			temp=a[i+1];
		}
		
        buildSA();
        getHeight();
		
		//二分枚举最短的不满足条件的
		int l=4,r=n;
		while(l<r){
			if(ok(mid)) l=mid+1;
			else r=mid;
		}
		printf("%d\n",l>=5?l:0);
        destroy();
    }
    return 0;
}

  

以上是关于POJ-1743 Musical Theme(后缀数组)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1743-Musical Theme-后缀数组

POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])

POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])

POJ 1743 Musical Theme ——后缀数组

POJ-1743 Musical Theme(后缀数组)

POJ-1743 Musical Theme(最长不可重叠子串,后缀数组+二分)