zoukankan      html  css  js  c++  java
  • [BZOJ3230] 相似字串 后缀数组+RMQ

    3230: 相似子串

    Time Limit: 20 Sec  Memory Limit: 128 MB

    Description

    Input

    输入第1行,包含3个整数N,Q。Q代表询问组数。
    第2行是字符串S。
    接下来Q行,每行两个整数i和j。(1≤i≤j)。

    Output

    输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。

    Sample Input

    5 3
    ababa
    3 5
    5 9
    8 10

    Sample Output

    18
    16
    -1

    HINT

    样例解释

    第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。

    第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。

    第3组询问:不存在第10个子串。输出-1。数据范围

    N≤100000,Q≤100000,字符串只由小写字母'a'~'z'组成 

    题解: 首先我们要解决的是本质不同的子串计数问题:

    考虑到子串一定是后缀的前缀,我们按照rank顺序添加每个后缀,

    那么每添加一个新后缀就会产生n-sa+1个新的前缀(子串)

    但是由于lcp的存在,这些子串又和前面的那一串重复的一些

    所以最后的计算式是Σn-sa+1-height,当然具体的细节,诸如±1会随代码风格和计算方式略有不同,读者自行修改即可

    接着我们考虑,本题其实就是让我们求某两个子串最长公共前缀和最长公共后缀

    这样我们可以跑一个SA之后把字串反转再求一套,我们就得到了后缀数组和一个诡异的"前缀数组"

    接着我们二分找到子串对应的端点以及后缀,再用rmq求一下lcp区间最小值即可.

    代码实现(当时我调到意识模糊于是封装了一下233):

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long LL;
     6 const int N=100010;
     7 int n,xx[N],yy[N],cnt[N],bin[23];
     8 LL num[N];
     9 struct Fleet
    10 {
    11     int sa[N],height[N],rank[N],f[N][18];
    12     char s[N];
    13     int i,j,k,p,m;
    14     inline void get_sa()
    15     {
    16         int *x=xx,*y=yy;m=256;
    17         for(i=0;i<m;++i)cnt[i]=0;
    18         for(i=0;i<n;++i)++cnt[x[i]=s[i]];
    19         for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
    20         for(i=n-1;~i;--i)sa[--cnt[x[i]]]=i;
    21         for(k=1,p=0;p<n&&k<=n;k<<=1,m=p)
    22         {
    23             for(p=0,i=n-k;i<n;++i)y[p++]=i;
    24             for(i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
    25             for(i=0;i<m;++i)cnt[i]=0;
    26             for(i=0;i<n;++i)++cnt[x[y[i]]];
    27             for(i=1;i<m;++i)cnt[i]+=cnt[i-1];
    28             for(i=n-1;~i;--i)sa[--cnt[x[y[i]]]]=y[i];
    29             for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;++i)
    30                 x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p-1:p++;
    31         }
    32     }
    33     inline void get_rank()
    34     {
    35         for(i=0;i<n;++i)rank[sa[i]]=i;
    36         for(k=i=0;i<n;height[rank[i++]]=k)
    37             for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
    38     }
    39     inline void ST()
    40     {
    41         for(i=0;i<n;++i)f[i][0]=height[i];
    42         for(i=1;bin[i]<=n;++i)
    43             for(j=0;j+bin[i]-1<n;++j)
    44                 f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
    45     }
    46     inline LL query(int l,int r)
    47     {
    48         int len=r-l+1,k=0;
    49         while(bin[k+1]<=len)++k;
    50         return min(f[l][k],f[r-bin[k]+1][k]);
    51     }
    52     inline void get_kth(int &st,int &ed,LL rk)
    53     {
    54         int ans=lower_bound(num,num+n,rk)-num;
    55         st=sa[ans],ed=st+height[ans]-1+rk-num[ans-1];
    56     }
    57     inline void intn()
    58         {get_sa(),get_rank(),ST();}
    59     inline void calc()
    60         {for(i=0;i<n;++i)num[i]=num[i-1]+LL(n-sa[i]-height[i]-1);}
    61 }Sfx,Pre;
    62 inline LL get_length(LL id1,LL id2)
    63 {
    64     register int i,j,k,st[2],ed[2];
    65     Sfx.get_kth(st[0],ed[0],id1);
    66     Sfx.get_kth(st[1],ed[1],id2);
    67     LL val=min(ed[0]+1ll-st[0],ed[1]+1ll-st[1]),tmp=val;
    68     if(st[0]!=st[1])
    69         if(Sfx.rank[st[0]]<Sfx.rank[st[1]])
    70             tmp=min(tmp,Sfx.query(Sfx.rank[st[0]]+1,Sfx.rank[st[1]]));
    71         else
    72             tmp=min(tmp,Sfx.query(Sfx.rank[st[1]]+1,Sfx.rank[st[0]]));
    73     ed[0]=n-2-ed[0],ed[1]=n-2-ed[1];
    74     if(ed[0]!=ed[1])
    75         if(Pre.rank[ed[0]]<Pre.rank[ed[1]])
    76             val=min(val,Pre.query(Pre.rank[ed[0]]+1,Pre.rank[ed[1]]));
    77         else
    78             val=min(val,Pre.query(Pre.rank[ed[1]]+1,Pre.rank[ed[0]]));
    79     return tmp*tmp+val*val;
    80 }
    81 int main()
    82 {
    83     register int i,j,m,a,b,q;LL u,v;
    84     scanf("%d%d%s",&n,&m,Sfx.s);
    85     for(bin[0]=i=1;i<=20;++i)bin[i]=bin[i-1]<<1;
    86     for(i=1;i<=n;++i)Pre.s[i-1]=Sfx.s[n-i];
    87     Sfx.s[n]=Pre.s[n]=1,n++;
    88     Sfx.intn();Pre.intn();Sfx.calc();
    89     while(m--)
    90     {
    91         scanf("%lld%lld",&u,&v);
    92         if(u>num[n-1]||v>num[n-1])printf("-1
    ");
    93         else printf("%lld
    ",get_length(u,v));
    94     }
    95 }
  • 相关阅读:
    PowerBuilder 前景(转贴)
    利用Lucene.net搭建站内搜索(3)创建索引
    执行力差的五大原因
    js关于document和window对象_javascript教程
    HTML内部链接
    深入理解 __doPostBack (转帖)
    利用Lucene.net搭建站内搜索(4)数据检索
    a href=#与 a href=javascript:void(0) 的区别 打开新窗口链接的几种办法
    Javascript进阶 (转帖)
    windows通过VNC连接linux (Fedora 12)
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7534667.html
Copyright © 2011-2022 走看看