题意:给定一个长度为n的下标从0开始的小写字母字符串,每次对于当前的i寻找一个j使得后缀i与后缀j的lcp最大,(j<i)若lcp相同则取较小的
若lcp为0则输出0与当前字符,i自增1,否则输出lcp的值与j,i自增lcp的值,以上过程重复直到i>=n
要求模拟这个过程
n<=1e5,sigma n<=2e6
思路:显然后缀的lcp要用到后缀数组
考虑对于每一个i都直接枚举j不可做,对于rank而言可以预处理出每一段连续的height大于0的起始位置和结束位置,在段中往左右两侧暴力枚举
满足要求的条件为:sa[j]<i,且连续的height的min的值不减
这个暴力扫描的复杂度应该假了(真的吗),但数据卡不掉……
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 typedef long long ll; 6 using namespace std; 7 #define N 110000 8 #define oo 10000000 9 #define MOD 100000073 10 11 12 char ch[N]; 13 int n,i,s[N],sa[N],wa[N],wb[N],wc[N],wd[N],height[N],Rank[N],pre[N],nxt[N]; 14 15 bool cmp(int *r,int a,int b,int l) 16 { 17 return r[a]==r[b]&&r[a+l]==r[b+l]; 18 } 19 20 void getsa(int *r,int *sa,int n,int m) 21 { 22 int *x=wa,*y=wb,j,p; 23 for(i=0;i<n;i++) wc[x[i]=r[i]]++; 24 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 25 for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i; 26 for(j=1,p=1;p<n;j*=2,m=p) 27 { 28 p=0; 29 for(i=n-j;i<n;i++) y[p++]=i; 30 for(i=0;i<n;i++) 31 if(sa[i]>=j) y[p++]=sa[i]-j; 32 for(i=0;i<n;i++) wd[i]=x[y[i]]; 33 for(i=0;i<m;i++) wc[i]=0; 34 for(i=0;i<n;i++) wc[wd[i]]++; 35 for(i=1;i<m;i++) wc[i]+=wc[i-1]; 36 for(i=n-1;i>=0;i--) sa[--wc[wd[i]]]=y[i]; 37 swap(x,y); 38 p=1; x[sa[0]]=0; 39 for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 40 if(j>n) break; 41 } 42 } 43 44 void getheight(int *r,int *sa,int n) 45 { 46 int i,j,k=0; 47 for(i=1;i<=n;i++) Rank[sa[i]]=i; 48 for(i=0;i<n;height[Rank[i++]]=k) 49 { 50 if(k) k--; 51 j=sa[Rank[i]-1]; 52 while(r[i+k]==r[j+k]) k++; 53 } 54 } 55 56 void init() 57 { 58 memset(s,0,sizeof(s)); 59 memset(sa,0,sizeof(sa)); 60 memset(wa,0,sizeof(wa)); 61 memset(wb,0,sizeof(wb)); 62 memset(wc,0,sizeof(wc)); 63 memset(wd,0,sizeof(wd)); 64 memset(height,0,sizeof(height)); 65 memset(Rank,0,sizeof(Rank)); 66 } 67 68 int main() 69 { 70 int cas; 71 scanf("%d",&cas); 72 for(int v=1;v<=cas;v++) 73 { 74 init(); 75 printf("Case #%d: ",v); 76 scanf("%s",ch); 77 n=strlen(ch); 78 for(int i=0;i<n;i++) s[i]=ch[i]-'a'+1; 79 s[n]=0; 80 getsa(s,sa,n+1,100); 81 getheight(s,sa,n); 82 for(int i=1;i<=n;i++) 83 if(!height[i]) pre[i]=i; 84 else pre[i]=pre[i-1]; 85 for(int i=n;i>=1;i--) 86 if(height[i+1]==0||i==n) nxt[i]=i; 87 else nxt[i]=nxt[i+1]; 88 int i=0; 89 while(i<n) 90 { 91 int now=Rank[i]; 92 int k=0; 93 int t=i; 94 int mn=height[now]; 95 for(int j=now-1;j>=pre[now];j--) 96 { 97 mn=min(mn,height[j+1]); 98 if(mn<k) break; 99 if(sa[j]<i) 100 { 101 if(mn>k||mn==k&&sa[j]<t) 102 { 103 k=mn; t=sa[j]; 104 } 105 } 106 } 107 if(now+1<=nxt[now]) mn=height[now+1]; 108 for(int j=now+1;j<=nxt[now];j++) 109 { 110 mn=min(mn,height[j]); 111 if(mn<k) break; 112 if(sa[j]<i) 113 { 114 if(mn>k||mn==k&&sa[j]<t) 115 { 116 k=mn; t=sa[j]; 117 } 118 } 119 } 120 if(!k) 121 { 122 printf("-1 %d ",ch[i]); 123 i++; 124 } 125 else 126 { 127 printf("%d %d ",k,t); 128 i+=k; 129 } 130 } 131 } 132 return 0; 133 } 134