题意:从第一个字符开始,找到一个从0到当前位置i之前的与i开始的字符串的最长匹配长度及位置,长度相同时,要位置小的,若存在,位置+最长长度,否则+1
思路:15年合肥的现场题目,据说牌子发不完了,这道题的题目数据变弱后才可以将牌子发光,HDU的应该也是弱数据的版本,但是也不太好处理,看了大牛的思路才自己照着样子写了写,大牛的做法,其实我就是完全的按照神犇的做法写的,大家可以去看他的博客,思路就是对于当前的位置i,它的排名找出来,然后它的前边和后边是可能有与其有匹配情况的,也只有这个情况才能匹配,然后找这两部分就行,如果已经找到的长度是K,那么当下一个长度不够K时,跳出即可,这样看i与i+1的匹配长度为L,i+1与i+2的匹配长度为L1,那么i与i+2的匹配长度一定是两者取小的那个,所以再找到一个比K小的,后面都是比K小的,这样就降低了复杂度,但是还是不知道能不能过了现场的题目,然后先是预处理一下左右可到的区间,这都是在高度数组上进行的,然后跑一遍找就可以了,写到这发现其实不予处理也可以,因为那个小于K那个已经很优化了,刚刚测试一下,也过了,慢了一点而已
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int MAXN=1000010;
int wa[MAXN],wb[MAXN],wv[MAXN],ww[MAXN];
int sa[MAXN],lcp[MAXN],Rank[MAXN],rank1[MAXN],vis[MAXN];
char str[MAXN];
inline bool cmp(int *r,int a,int b,int len){
return r[a]==r[b]&&r[a+len]==r[b+len];
}
void construct_sa(int n,int m){
int i,j,p,*x=wa,*y=wb,*t;n++;
for(i=0;i<m;i++) ww[i]=0;
for(i=0;i<n;i++) ww[x[i]=str[i]]++;
for(i=1;i<m;i++) ww[i]+=ww[i-1];
for(i=n-1;i>=0;i--) sa[--ww[x[i]]]=i;
for(j=p=1;p<n;j<<=1,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<m;i++) ww[i]=0;
for(i=0;i<n;i++) ww[wv[i]=x[y[i]]]++;
for(i=1;i<m;i++) ww[i]+=ww[i-1];
for(i=n-1;i>=0;i--) sa[--ww[wv[i]]]=y[i];
for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
void construct_lcp(int n){
for(int i=0;i<=n;i++) rank1[sa[i]]=i;
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++){
int j=sa[rank1[i]-1];
if(h>0) h--;
for(;j+h<n&&i+h<n;h++) if(str[i+h]!=str[j+h]) break;
lcp[rank1[i]-1]=h;
}
}
int fa[MAXN],son[MAXN];
int main(){
int T,cas=1;
scanf("%d",&T);
while(T--){
scanf("%s",str);
int len=strlen(str);
memset(fa,0,sizeof(fa));
memset(son,0,sizeof(son));
construct_sa(len,300);sa[len+1]=inf;
construct_lcp(len);
for(int i=1;i<=len;i++){
if(lcp[i-1]==0) fa[i]=i;
else fa[i]=fa[i-1];
}
for(int i=len;i>0;i--){
if(lcp[i]==0||i==len) son[i]=i;
else son[i]=son[i+1];
}
printf("Case #%d:\n",cas++);
for(int i=0;i<len;){
if(i==0){
printf("-1 %d\n",(int)str[i]);
i++;continue;
}
int min1=0,pos=inf,fen=rank1[i];
int max1;
max1=lcp[fen];
for(int j=fen;j<=son[fen];j++){
max1=min(max1,lcp[j]);
if(max1<min1) break;
if(sa[j+1]>=i) continue;
if(max1>min1){
min1=max1;pos=sa[j+1];
}else if(max1==min1&&pos>sa[j+1]) pos=sa[j+1];
}
if(fen-1>=fa[fen]) max1=lcp[fen-1];
for(int j=fen-1;j>=fa[fen];j--){
max1=min(max1,lcp[j]);
if(max1<min1) break;
if(sa[j]>=i) continue;
if(max1>min1){
min1=max1;pos=sa[j];
}else if(max1==min1&&pos>sa[j]) pos=sa[j];
}
if(min1==0){
printf("-1 %d\n",(int)str[i]);
i++;
}else{
printf("%d %d\n",min1,pos);
i+=min1;
}
}
}
return 0;
}