• 后缀数组 hash求LCP BZOJ 4310: 跳蚤


    后缀数组的题博客里没放进去过。。所以挖了一题写写 充实下博客 顺便留作板子。。

    一个字符串S中 内容不同的子串 有 sigma{n-sa[i]+1-h[i]}   (噢 这里的h[]就是大家熟知的height[])

    所以l=1,r=上述sigma 二分 答案是字典序第几大的子串。

    然后 求S中第k大的子串W : 因为h[i]是与i-1有关的 所以要从n downto 1,k-=n-sa[i]+1-h[i] 至 k再减就非正了

    显然这样扫过来 子串字典序是递减的  因此可以得到第k大子串W

    然后再贪心 n downto 1 若遇到比 W大的子串 就划分,验证 当前二分的这个第k大可不可行

    判断 比W大还是小 用hash 二分求LCP即可

     1 #include <bits/stdc++.h>
     2 #define N 200005
     3 #define LL long long
     4 using namespace std;
     5 const LL mo=1000000007;
     6 int F[27],a[N],rank[N],sa[N],h[N],g1[N],g2[N],next[N],n,m,ans,k,t,l,r,mid,x,y,z;
     7 char S[N]; LL f[N],w[N];
     8 int oh(int k,int t,int p,int q){
     9     int l=0,r=min(t-k,q-p)+1,j;
    10     while (l<r){
    11         j=l+r+1>>1;
    12         (f[k+j-1]-f[k-1]*w[j]%mo+mo)%mo==(f[p+j-1]-f[p-1]*w[j]%mo+mo)%mo?
    13         l=j:r=j-1;
    14     }
    15     if (k+l>t) return 0;
    16     if (p+l>q) return 1;
    17     return a[k+l]>a[p+l];
    18 }
    19 int jud(int u){
    20     int p,q,k,t;
    21     for (int i=n;i;--i)
    22         if (n-sa[i]+1-h[i]<u) u-=n-sa[i]+1-h[i];
    23         else {p=sa[i];q=n-u+1;break;}
    24     t=n; k=1;
    25     for (int i=n;i;)
    26     if (oh(i,t,p,q)){
    27         if (i==t) return 0;
    28         t=i; ++k;
    29     } else --i;
    30     if (k>m) return 0; return 1;
    31 }
    32 int main(){
    33     scanf("%d",&m); scanf("%s",S+1); n=strlen(S+1);
    34     w[0]=1;
    35     for (int i=1;i<=n;++i) {
    36         a[i]=S[i]-'a'+1;
    37         F[a[i]]=1;
    38         f[i]=(f[i-1]*29+a[i])%mo;
    39         w[i]=w[i-1]*29%mo;
    40     }
    41     for (int i=2;i<=26;++i) F[i]+=F[i-1];
    42     for (int i=1;i<=n;++i) rank[i]=F[a[i]]; t=F[26];
    43     for (int m=1;m<n;m<<=1){
    44         for (int i=1;i<=n;++i){
    45             next[i]=g1[rank[i+m]];
    46             g1[rank[i+m]]=i;
    47         }
    48         for (int i=t;i>=0;--i){
    49             for (int j=g1[i];j;j=k){
    50                 k=next[j]; next[j]=g2[rank[j]]; g2[rank[j]]=j;
    51             }
    52             g1[i]=0;
    53         }
    54         z=0;
    55         for (int i=1;i<=t;++i){
    56             y=-1;
    57             for (int j=g2[i];j;j=k){
    58                 k=next[j]; next[j]=0;
    59                 if (y!=rank[j+m]) y=rank[j+m],++z;
    60                 h[j]=z;
    61             }
    62             g2[i]=0;
    63         }
    64         t=z;
    65         for (int i=1;i<=n;++i) rank[i]=h[i];
    66     }
    67     for (int i=1;i<=n;++i) sa[rank[i]]=i,h[i]=0;
    68     for (int i=1,k=0;i<=n;++i)
    69     if (rank[i]!=1){
    70         if (k) --k;
    71         while (a[i+k]==a[sa[rank[i]-1]+k]) ++k;
    72         h[rank[i]]=k; r+=n-i+1-k;
    73     }
    74     l=1; ++r;
    75     while (l<r){
    76         k=l+r+1>>1;
    77         jud(k)?l=k:r=k-1;
    78     }
    79     for (int i=n;i;--i)
    80     if (n-sa[i]+1-h[i]<l) l-=n-sa[i]+1-h[i];
    81     else {k=sa[i];t=n-l+1;break;}
    82     for (int i=k;i<=t;++i) printf("%c",a[i]+'a'-1);
    83     return 0;
    84 }
    Assassin
    转载请标明出处 http://www.cnblogs.com/cyz666/
  • 相关阅读:
    【LeetCode每天一题】Rotate List(旋转链表)
    【LeetCode每天一题】Permutation Sequence(排列序列)
    【LeetCode每天一题】Length of Last Word(字符串中最后一个单词的长度)
    【LeetCode每天一题】Merge Intervals(合并区间)
    【LeetCode每天一题】Spiral Matrix II(螺旋数组II)
    Ajax基础
    git的命令行操作
    新闻发布系统之登录和注销
    JSTL和EL
    servlet模板的修改
  • 原文地址:https://www.cnblogs.com/cyz666/p/6431140.html
Copyright © 2020-2023  润新知