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 }
posted @ 2018-04-02 15:26  hehe_54321  阅读(142)  评论(0编辑  收藏  举报
AmazingCounters.com