BZOJ 1396||2865 识别子串
这个不是题解,看不懂的,别看了
明明应该是会的,怎么还是写了6个小时呢。。。
把后缀数组、height数组、排名数组求出来,那么对于原串s的任意子串[x,y](表示第x个到第y个字符组成的子串,字符从1开始编号),就有了O(1)判断其在原串中出现次数是否大于1的方法
bool more1(int x,int y) { int t1=rk[x]>1?height[rk[x]]:-1,t2=rk[x]<n?height[rk[x]+1]:-1; return t1>=y-x+1||t2>=y-x+1; }
就是找到x在后缀数组中的排名rk[x],再找到后缀sa[rk[x]]与后缀sa[rk[x]-1]的LCP即t1,后缀sa[rk[x]]与后缀sa[rk[x]+1]的LCP即t2,如果t1,t2的最小值都小于y-x+1,则表示后缀sa[rk[x]-1]和后缀sa[rk[x]+1]的前y-x+1位都不与后缀sa[rk[x]]的前y-x+1位相同,即子串[x,y]只出现了一次(因为如果出现超过一次,那么子串[x,y]至少是后缀sa[rk[x]-1]和后缀sa[rk[x]+1]中一个的前缀);否则表示子串[x,y]出现了大于1次。
然而为什么我想不到呢。。。
记从第l位开始的最短识别子串的右端点为a[l],则a数组显然是不下降的(也可能从第l位开始的所有子串中不存在识别子串,那么将其特殊标记为不存在即可)
那么用双指针法结合上面的函数,可以在O(n)的时间内求出整个a数组
最终位置i的答案ans[i]=min(min{a[l]-l+1}(l<=i<=a[l]),min{i-l+1}(i>a[l]))
ans[i]=min(min{a[l]-l+1}(l<=i<=a[l]),i+min{-l+1}(i>a[l]))
曾经错误1:ans[i]=min(min{a[l]-l+1}(i<=a[l]),i+min{-l+1}(i>a[l]))
注意到min{a[l]-l+1}(l<=i<=a[l])可以用线段树或单调队列维护,min{-l+1}(i>a[l])可以用前缀min(?)预处理,因此搞一下就行了
所以说为什么我又调了两个小时才调出来一个可行的算法呢。。。
(bzoj权限题,没有交过)
曾经错误2:26行
记从位置l开始的最短识别子串的右端点为a[l],则a[l]不下降
对于位置i的答案,
ans[i]=min(min{a[l]-l+1}(l<=i<=a[l]),i+min{-l+1}(i>a[l]))
对于b a n a n a
a : 1 2 3 4 5 6
1 5 5 -1 -1 -1
a[l] 1 2 3 4 5
a[l]-l+1 1 3
-l+1 0 -2
ans 1 2 3 4 5 6
1 2 3 3 3 4
令t1[i]=min{a[l]-l+1}(a[l]>=i)
t1[i]=min(t1[i+1],a[l]-l+1)(a[l]==i)
t2[i]=min{-l+1}(a[l]<=i)
babbb
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 char s[100100]; 6 int n; 7 namespace SA 8 { 9 int sa[100100],t1[100100],t2[100100],m=128,cnt[100100],p; 10 int *x=t1,*y=t2,*rk=t1,*height=t2; 11 template<typename T> 12 T get(int pos,T *a) 13 { 14 return pos<=n?a[pos]:0; 15 } 16 void build() 17 { 18 int i,k; 19 for(i=1;i<=n;i++) cnt[x[i]=s[i]]++; 20 for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; 21 for(i=n;i>=1;i--) sa[cnt[x[i]]--]=i; 22 for(k=1;k<=n;k<<=1) 23 { 24 p=0; 25 for(i=n-k+1;i<=n;i++) y[++p]=i; 26 //for(i=1;i<=n;i++) if(sa[i]>=k) y[++p]=sa[i]-k; 27 for(i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k; 28 for(i=1;i<=m;i++) cnt[i]=0; 29 for(i=1;i<=n;i++) cnt[x[y[i]]]++; 30 for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; 31 for(i=n;i>=1;i--) sa[cnt[x[y[i]]]--]=y[i]; 32 swap(x,y);p=0; 33 for(i=1;i<=n;i++) 34 x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&get(sa[i]+k,y)==get(sa[i-1]+k,y) 35 ?p:++p; 36 if(p>=n) break; 37 m=p; 38 } 39 for(i=1;i<=n;i++) rk[sa[i]]=i; 40 for(i=1,k=1;i<=n;i++) 41 { 42 if(k) k--; 43 if(rk[i]) 44 while(get(sa[rk[i]-1]+k,s)==get(i+k,s)) k++; 45 height[rk[i]]=k; 46 } 47 } 48 bool more1(int x,int y) 49 { 50 int t1=rk[x]>1?height[rk[x]]:-1,t2=rk[x]<n?height[rk[x]+1]:-1; 51 return t1>=y-x+1||t2>=y-x+1; 52 } 53 } 54 int l,r,a[100100]; 55 int t1[100100],t2[100100]; 56 int main() 57 { 58 int i; 59 scanf("%s",s+1);n=strlen(s+1);SA::build(); 60 memset(t2,0x3f,sizeof(t2));memset(a,0x3f,sizeof(a)); 61 for(l=1;l<=n;l++) 62 { 63 if(l>r) r=l; 64 while(r<=n&&SA::more1(l,r)) r++; 65 //printf("%d %d\n",l,r); 66 if(r<=n) 67 { 68 a[l]=r; 69 t2[r]=min(t2[r],-l+1); 70 } 71 } 72 for(i=1;i<=n;i++) t2[i]=min(t2[i-1],t2[i]); 73 //for(i=1;i<=n;i++) printf("%d\n",t2[i]); 74 l=1;r=0; 75 for(i=1;i<=n;i++) 76 { 77 if(a[i]!=0x3f3f3f3f) 78 { 79 while(l<=r&&a[t1[r]]-t1[r]+1>=a[i]-i+1) --r; 80 t1[++r]=i; 81 } 82 while(l<=r&&a[t1[l]]<i) ++l; 83 printf("%d\n",min(l<=r?a[t1[l]]-t1[l]+1:0x3f3f3f3f,i+t2[i])); 84 } 85 return 0; 86 }