首页 > 编程语言 > 详细

后缀数组基本问题QAQ

时间:2017-01-18 00:51:06      阅读:323      评论:0      收藏:0      [点我收藏+]

以下题目均来自罗穗骞的论文...

No.1最长公共前缀

最长公共前缀:

题目:

给定一个字符串,询问某两个后缀的最长公共前缀。

分析:

某两个后缀的最长公共前缀就是区间height最小值,转化为RMQ问题,nlgn预处理,O(1)询问...

No.2单个字符串的相关问题

1、重复子串

可重叠最长重复子串:

题目:

给定一个字符串,求最长重复子串,这两个子串可以重叠。

分析:

就是height数组的最大值...

不可重叠最长重复子串(POJ1743)

题目:

给定一个字符串,求最长重复子串,这两个子串不能重叠。

这道题有一个特殊要求是如果一个子串的每个数同时加上一个相同的数字所得到的子串也在字符串中出现的话也是重复子串...

分析:

我们先忽略特殊要求只考虑普通的重复子串...

首先我们通过二分答案把最优性问题转化为可行性问题...

我们二分最长的重复字串的长度为len,然后我们根据len把sa按照height数组分组,我们把sa分成若干组,保证每一组的height最小值都大于等于len,这样就保证了组内的最长公共前缀是大于等于len的,现在要求不重复,就是要求最长公共前缀大于等于len的两个后缀的开头距离是大于等于len的,这样就保证了不重复...

现在考虑特殊要求,因为整体加数相同的话说,差分之后也应该相同,所以我们把n个数通过差分变成n-1个数,其他的照旧,只不过开头距离大于len的才合法...(因为是差分之后的...)

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
//良辰美景奈何天,赏心乐事谁家院 

const int maxn=200000+5;

int n,s[maxn],gs[maxn],wv[maxn],wb[maxn],sa[maxn],rank[maxn],height[maxn]; 

inline int read(void){
	char ch=getchar();int x=0;
	while(!(ch>=‘0‘&&ch<=‘9‘))
		ch=getchar();
	while(ch>=‘0‘&&ch<=‘9‘)
		x=x*10+ch-‘0‘,ch=getchar();
	return x;
}

inline bool cmp(int *x,int a,int b,int l){
	return x[a]==x[b]&&x[a+l]==x[b+l];
}

inline void da(int *sa,int *x,int n,int m){
	int i,j,p,*y=wb;
	for(i=0;i<m;i++) gs[i]=0;
	for(i=0;i<n;i++) gs[x[i]]++;
	for(i=1;i<m;i++) gs[i]+=gs[i-1];
	for(i=n-1;~i;i--) sa[--gs[x[i]]]=i;
	for(j=1,p=1;p<n;j<<=1,m=p){
		for(i=n-j,p=0;i<n;i++) y[p++]=i;
		for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
		for(i=0;i<n;i++) wv[i]=x[y[i]];
		for(i=0;i<m;i++) gs[i]=0;
		for(i=0;i<n;i++) gs[wv[i]]++;
		for(i=1;i<m;i++) gs[i]+=gs[i-1];
		for(i=n-1;~i;i--) sa[--gs[wv[i]]]=y[i];
		p=1;swap(x,y);x[sa[0]]=0;
		for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
	}
}

inline void calheight(int n){
	int i,j,k=0;
	for(i=0;i<=n;i++) rank[sa[i]]=i;
	for(i=0;i<n;height[rank[i++]]=k)
		for(k?k--:233,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
}

inline bool check(int x){
	int Max=0,Min=n;bool ans=0;
	for(int i=2;i<=n&&ans==0;i++){
		if(height[i]<x){
			if(Max!=0)
				if(Max-Min>x)
					ans=1;
			Min=Max=sa[i];
			continue;
		}
		Max=max(Max,sa[i]),Min=min(Min,sa[i]);
	}
	if(Max!=0&&Max-Min>x)
		ans=1;
	return ans;
}

signed main(void){
	while(n=read()){
		memset(s,0,sizeof(s));
		memset(gs,0,sizeof(gs));
		memset(wb,0,sizeof(wb));
		memset(wv,0,sizeof(wv));
		memset(sa,0,sizeof(sa));
		memset(rank,0,sizeof(rank));
		memset(height,0,sizeof(height));
		for(int i=0;i<n;i++)
			s[i]=read();
		if(n<10){
			puts("0");continue;
		}
		n--;
		for(int i=0;i<n;i++)
			rank[i]=s[i]=s[i+1]-s[i]+100;
		s[n]=0;
		da(sa,rank,n+1,200);calheight(n);
		int l=4,r=n>>1,ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid))
				ans=mid,l=mid+1;
			else
				r=mid-1;
		}
		printf("%d\n",ans+1);
	}
	return 0;
}//Cap ou pas cap. Pas cap.

可重叠k次的最长重复子串(POJ3261)

 未完待续...


By NeighThorn

后缀数组基本问题QAQ

原文:http://www.cnblogs.com/neighthorn/p/6291738.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!