51nod-1732 婚姻介绍所(后缀数组)

题目大意:回答任意两个子串的最长公共前缀。

题目分析:后缀数组的模板题。但是输入输出都要外挂。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;

const int N=1000;

int n,m;
char s[N+5];
int cnt[N+5],SA[N+5];
int rk[N+5],tSA[N+5];
int height[N+5];
int ans[N+5][N+5];

void in(int &x)
{
	x=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	x=c-'0';
	while(c=getchar()){
		if(c<'0'||c>'9') break;
		x=x*10+c-'0';
	}
}

void out(int x)
{
	if(x>=10)
		out(x/10);
	putchar(x%10+'0');
}

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

void buildSA()
{
	m=130;
	int *x=rk,*y=tSA;
	for(int i=0;i<m;++i) cnt[i]=0;
	for(int i=0;i<n;++i) ++cnt[x[i]=s[i]];
	for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
	for(int i=n-1;i>=0;--i) SA[--cnt[x[i]]]=i;
	for(int k=1;k<=n;k<<=1){
		int p=0;
		for(int i=n-k;i<n;++i) y[p++]=i;
		for(int i=0;i<n;++i) if(SA[i]>=k) y[p++]=SA[i]-k;
		for(int i=0;i<m;++i) cnt[i]=0;
		for(int i=0;i<n;++i) ++cnt[x[y[i]]];
		for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];
		for(int i=n-1;i>=0;--i) SA[--cnt[x[y[i]]]]=y[i];
		p=1;
		swap(x,y);
		x[SA[0]]=0;
		for(int i=1;i<n;++i){
			if(same(y,i,i-1,k)) x[SA[i]]=p-1;
			else x[SA[i]]=p++;
		}
		if(p>=n) break;
		m=p;
	}
}

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

void getAns()
{
	for(int i=0;i<n;++i) ans[i][i]=n-i;
	for(int i=0;i<n;++i){
		int minn=n;
		for(int j=i+1;j<n;++j){
			minn=min(minn,height[j]);
			ans[SA[i]][SA[j]]=ans[SA[j]][SA[i]]=minn;
		}
	}
}

int main()
{
	int q,a,b;
	while(~scanf("%d",&n))
	{
		scanf("%s",s);
		buildSA();
		getHeight();
		getAns();
		in(q);
		while(q--)
		{
			in(a);
			in(b);
			out(ans[a][b]);
			puts("");
		}
	}
	return 0;
}

  

 

posted @ 2016-09-08 13:56  20143605  阅读(280)  评论(0编辑  收藏  举报