算是后缀数组的入门题吧。 思路无比简单,要是直接套模板的话应该很容易秒掉。
关于后缀数组看高中神犇的论文就可以学会了
话说这题暴力是可以过了,但是我们在做多校的时候就是用暴力过的,当时还不知道什么是后缀数组。。。
靠着概念纯手敲了几个小时,把建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