算是后缀数组的入门题吧。 思路无比简单,要是直接套模板的话应该很容易秒掉。
关于后缀数组看高中神犇的论文就可以学会了
话说这题暴力是可以过了,但是我们在做多校的时候就是用暴力过的,当时还不知道什么是后缀数组。。。
靠着概念纯手敲了几个小时,把建SA,求height,和RMQ的ST算法都复习了一遍,这个东西要是每次都手敲的话真的会死人,尤其是倍增算法基数排序怎么排怎么别扭。自己写的倍增算法又太长,大牛的倍增算法总感觉敲的不顺。
贴个代码做留念。。。
Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 1344    Accepted Submission(s): 500

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define N 100100
char g[N];
int r[N];
int sa[N];
int scnt[N];
int wa[N],wb[N],wv[N];
int mrank[N];
int h[N],th[N];
int dp[N][22];
int save[N];
int cmp(int gg[],int a,int b,int k)
{
	return gg[a]==gg[b] && gg[a+k]==gg[b+k];
}
void getsa(int str[],int sa[],int n,int m)
{
	int i,j,*x,*y,*t;
	x=wa; y=wb;
	memset(scnt,0,sizeof(scnt));
	for(i=0;i<n;i++)
		scnt[ x[i]=str[i] ]++;
	for(i=1;i<m;i++)
		scnt[i]+=scnt[i-1];
	for(i=0;i<n;i++)
		sa[ --scnt[ str[i] ] ]=i;
	for(int p=1,j=1;p<n;j*=2,m=p)
	{
		for(p=0,i=n-j;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] ];
		memset(scnt,0,sizeof(scnt));
		for(i=0;i<n;i++) scnt[ wv[i] ]++;
		for(i=1;i<m;i++) scnt[i]+=scnt[i-1];
		for(i=n-1;i>=0;i--) sa[ --scnt[ wv[i] ] ] = y[i];
		for(p=1,t=x,x=y,y=t,x[sa[0]]=0,i=1;i<n;i++)
			x[ sa[i] ] = cmp(y,sa[i],sa[i-1],j)?p-1:p++;
	}
}
void geth(int str[],int n)
{
	h[n-1]=0;
	int p=0;
	for(int i=0;i<n-1;i++)
	{
		int tmp=mrank[i];
		while( str[i+p] == str[ sa[tmp-1]+p ] ) p++;
		h[i]=p;
		p--;
		p=max(0,p);
	}
}
void buildst(int n)
{
	for(int i=1;i<=n;i++)
		dp[i][0] = th[i];
	for(int i=1;(1<<i)<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if( j+(1<<(i-1)) >n ) dp[j][i]=dp[j][i-1];
			else dp[j][i]=min(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
		}
	}
}
int cal(int x,int y)
{
	if(x>y) swap(x,y);
	x++;
	//然后就是求x到y的最小值
	int k=0;
	while( (1<<k)<=(y-x+1) ) k++;
	k--;
	return min(dp[x][k],dp[y-(1<<k)+1][k]);
}
int main()
{
	while(scanf("%s",g)!=EOF)
	{
		int len=strlen(g);
		for(int i=0;i<len;i++)
			r[i]=g[i];
		r[len++]=0;
		getsa(r,sa,len,300);
		for(int i=0;i<len;i++)
			mrank[ sa[i] ]=i;
		//for(int i=0;i<len;i++) printf("%s\n",g+sa[i]);
		geth(r,len);
		for(int i=0;i<len-1;i++)
			th[ mrank[i] ]= h[i];
		buildst(len-1);
		int m;
		long long ans1=0,ans2=0;
		scanf("%d",&m);
		int x,y,tmp;
		scanf("%d%d",&x,&y);
		ans1+=y-x;
		ans2+=y-x;
		save[1]=0;
		for(int i=2;i<=m;i++)
		{
			int tx,ty;
			scanf("%d%d",&tx,&ty);
			ans1+=ty-tx;
			int cnt;
			if(tx==x)
				cnt=len-1-tx;
			else
				cnt=cal(mrank[tx],mrank[x]);
			save[i]=min(ty-tx,min(y-x,cnt));
			ans2+=ty-tx-save[i];
			x=tx; y=ty;
		}
		ans1+=m;
		ans2+=m+m;
		for(int i=1;i<=m;i++)
		{
			ans2++;
			save[i]/=10;
			while(save[i])
			{
				ans2++;
				save[i]/=10;
			}
		}
		cout<<ans1<<" "<<ans2<<endl;
	}
    return 0;
}
原文:http://www.cnblogs.com/chenhuan001/p/4017853.html