zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",min(l<=r?a[t1[l]]-t1[l]+1:0x3f3f3f3f,i+t2[i]));
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    用JS实现气泡效果
    如何判断浏览器JS代码
    你是怎么看完《JavaScript权威指南》《JavaScript高级程序设计》等这类厚书的?
    CSS3技巧:fit-content水平居中
    捋一捋JavaScript对象的理解
    js 判断数据类型的几种方法
    给想转行学习web前端的朋友提些学习建议及学习路线
    sentry 9.1.1docker版onepremise过程记录
    python内置函数all使用的坑
    centos7.2自带的php5.4升级为5.6
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8693771.html
Copyright © 2011-2022 走看看