• 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)


    3473: 字符串

    Description

    给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串?

    Input

    第一行两个整数n,k。
    接下来n行每行一个字符串。

    Output

    一行n个整数,第i个整数表示第i个字符串的答案。

    Sample Input

    3 1
    abc
    a
    ab

    Sample Output

    6 1 3

    HINT



    对于 100% 的数据,1<=n,k<=10^5,所有字符串总长不超过10^5,字符串只包含小写字母。

    【分析】

      这道题用后缀数组的被SAM完爆了..貌似...

        首先将所有字符串串在一次做SA,然后我们对于sa上,枚举每个串的每个后缀,求出有几个该后缀的前缀符合条件,那么就要判定区间里面有多少个不同的数,所幸的是这里只需要求是否该数目>=k,所以对于每个位置记录个L(x),表示[L(x),x]中刚好有k个不同的数,且L(x)与x距离最大(参考了CF官方题解)。(这里弄几条链O(n)可以搞出来)

      然后CF上的题解是对于每个后缀二分出长度l,在排好序的后缀上查找最前最后端点使min(这一段的height)>=l。 (这里用到二分+RMQ)

      接下来是去掉一个log的优化:(即1上面的二分长度l改成直接从上一个的位置开始for)

    那么我们发现枚举后缀的时候,如果后缀c+S有n个前缀合法(c表示一个字符,s表示一个串),那么对于后缀S,至少有n-1个前缀合法(如果c+S有n个前缀出现不小于k次,那么其子串也是),那么我们就用类似求SA里的height一样的方法,记录一下前面的后缀的合法前缀数,然后这样的总复杂度就成了均摊。

    搬运:http://www.cnblogs.com/zyfzyf/p/4149536.html

      类似求height的那个优化好厉害!!!

      记得用long long~~

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 200010
      9 #define LL long long
     10 
     11 int n,k;
     12 char s[Maxn];
     13 int a[Maxn],bl[Maxn],cl;
     14 
     15 int mymin(int x,int y) {return x<y?x:y;}
     16 
     17 void init()
     18 {
     19     scanf("%d%d",&n,&k);
     20     cl=0;
     21     for(int i=1;i<=n;i++)
     22     {
     23         scanf("%s",s+1);
     24         int len=strlen(s+1);
     25         for(int j=1;j<=len;j++) a[++cl]=s[j]-'a'+1,bl[cl]=i;
     26         a[++cl]=28,bl[cl]=-1;
     27     }
     28 }
     29 
     30 int sa[Maxn],y[Maxn],rk[Maxn],Rs[Maxn],wr[Maxn];
     31 void get_sa(int m)
     32 {
     33     memcpy(rk,a,sizeof(rk));
     34     for(int i=0;i<=m;i++) Rs[i]=0;
     35     for(int i=1;i<=cl;i++) Rs[rk[i]]++;
     36     for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     37     for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;
     38     
     39     int ln=1,p=1;
     40     while(p<cl)
     41     {
     42         int k=0;
     43         for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
     44         for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;
     45         for(int i=1;i<=cl;i++) wr[i]=rk[y[i]];
     46         
     47         for(int i=0;i<=m;i++) Rs[i]=0;
     48         for(int i=1;i<=cl;i++) Rs[wr[i]]++;
     49         for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     50         for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];
     51         
     52         // memcpy(wr,rk,sizeof(wr));
     53         for(int i=1;i<=cl;i++) wr[i]=rk[i];
     54         for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
     55         p=1;
     56         rk[sa[1]]=1;
     57         for(int i=2;i<=cl;i++)
     58         {
     59             if(wr[sa[i]]!=wr[sa[i-1]]||wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
     60             rk[sa[i]]=p;
     61         }
     62         
     63         ln*=2;m=p;
     64     }
     65 }
     66 
     67 int height[Maxn];
     68 void get_he()
     69 {
     70     int kk=0;
     71     for(int i=1;i<=cl;i++) if(rk[i]!=1)
     72     {
     73         int j=sa[rk[i]-1];
     74         if(kk) kk--;
     75         while(a[i+kk]==a[j+kk]&&i+kk<=cl&&j+kk<=cl) kk++;
     76         height[rk[i]]=kk;
     77     }
     78 }
     79 
     80 int g[Maxn],lt[Maxn],nt[Maxn],sm[Maxn];
     81 bool p[Maxn];
     82 void get_g()
     83 {
     84     memset(lt,0,sizeof(lt));
     85     for(int i=1;i<=cl;i++)
     86     {
     87         sm[i]=lt[bl[sa[i]]];
     88         lt[bl[sa[i]]]=i;
     89     }
     90     memset(lt,0,sizeof(lt));
     91     memset(p,0,sizeof(p));
     92     int h=0,now;
     93     for(int i=1;i<=cl;i++)
     94     {
     95         if(!p[bl[sa[i]]]) h++;
     96         p[bl[sa[i]]]=1;
     97         if(h==k) {now=i;break;}
     98     }int id=0;
     99     for(int i=now;i>=1;i--)
    100     {
    101         if(p[bl[sa[i]]])
    102         {
    103             h--;
    104             if(id)
    105             {
    106                 nt[i]=id;lt[id]=i;lt[i]=0;
    107             }
    108             id=i;
    109             p[bl[sa[i]]]=0;
    110         }
    111         if(h==0) {g[now]=i;break;}
    112     }
    113     for(int i=now+1;i<=cl;i++)
    114     {
    115         if(sm[i]>g[i-1])
    116         {
    117             g[i]=g[i-1];
    118             nt[now]=i;lt[i]=now;
    119             nt[lt[sm[i]]]=nt[sm[i]];
    120             lt[nt[sm[i]]]=lt[sm[i]];
    121         }
    122         else
    123         {
    124             nt[now]=i;lt[i]=now;
    125             g[i]=nt[g[i-1]];
    126         }
    127         now=i;
    128     }
    129 }
    130 
    131 int d[Maxn][20];
    132 void init_rmq()
    133 {
    134     for(int i=2;i<=cl;i++) d[i][0]=height[i];
    135     for(int j=1;(1<<j)<=cl;j++)
    136      for(int i=2;i+(1<<j)-1<=cl;i++)
    137       d[i][j]=mymin(d[i][j-1],d[i+(1<<j-1)][j-1]);    
    138 }
    139 
    140 int rmq(int l,int r)
    141 {
    142     int i=0;
    143     while(l+(1<<i)-1<=r) i++;
    144     return mymin(d[l][i-1],d[r-(1<<i-1)+1][i-1]);
    145 }
    146 
    147 int t_div(int l,int r,int x,int kk)
    148 {
    149     if(l>r) return x;
    150     while(l<r)
    151     {
    152         int mid;
    153         if(r<x)
    154         {
    155             mid=(l+r)>>1;
    156             if(rmq(mid+1,x)>=kk) r=mid;
    157             else l=mid+1;
    158         }
    159         else
    160         {
    161             mid=(l+r+1)>>1;
    162             if(rmq(x+1,mid)>=kk) l=mid;
    163             else r=mid-1;
    164         }
    165     }
    166     if(l<x&&rmq(l+1,x)>=kk) return l;
    167     if(l>x&&rmq(x+1,l)>=kk) return l;
    168     return x;
    169 }
    170 
    171 LL ans[Maxn];
    172 void ffind()
    173 {
    174     memset(ans,0,sizeof(ans));
    175     int mx=0;
    176     for(int i=1;i<=cl;i++) if(bl[i]!=-1)
    177     {
    178         int kk=1;
    179         if(mx>=i) kk=mx-i+2;
    180         while(1)
    181         {
    182             int l=t_div(1,rk[i]-1,rk[i],kk),r=t_div(rk[i]+1,cl,rk[i],kk);
    183             if(g[r]<l||bl[i+kk-1]!=bl[i]||i+kk-1>cl) {kk--;break;}
    184             kk++;
    185         }
    186         ans[bl[i]]+=kk;
    187         mx=i+kk-1;
    188     }
    189 }
    190 
    191 int main()
    192 {
    193     init();
    194     get_sa(30);
    195     get_he();
    196     get_g();
    197     init_rmq();
    198     ffind();
    199     for(int i=1;i<=n;i++) 
    200     {
    201         if(i!=1) printf(" ");
    202         printf("%lld",ans[i]);
    203     }
    204     return 0;
    205 }
    [BZOJ2473]

    2016-08-25 12:00:01


      233学了广义SAM的我回来更新这题了~~

      其实我还不是很懂。。

      看GDXB的题解:

    每个节点维护一个set,存它是哪个串的,然后整理一下parent tree从下往上合并set(他们说是启发式合并,然而我用了最普通的暴力合并)。
    最后每一个串在自动机上跑一遍,如果set的size<k就不断跳pre,保证当前的这一条后缀的前缀都是可行的,每个可行点的贡献是step[i]。

      广义SAM不能用step或者son求拓扑序,这个的pre更新用dfs即可。 (蒟蒻表示又被坑了!)

      统计答案的时候可以用step,大概是机上有原串吧~

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<cmath>
      8 #include<set>
      9 using namespace std;
     10 #define Maxn 100010
     11 #define LL long long
     12 
     13 char s[Maxn],ss[Maxn];
     14 int l,bg[Maxn];
     15 
     16 struct node
     17 {
     18     int pre,son[30],step;
     19 }t[2*Maxn];int tot=0;
     20 int last;
     21 
     22 set<int > d[2*Maxn];
     23 
     24 void upd(int x)
     25 {
     26     memset(t[x].son,0,sizeof(t[x].son));
     27     d[x].clear();
     28     t[x].pre=0;
     29 }
     30 
     31 void get_d(int x,int y)
     32 {
     33     if(x==0) return;
     34     set<int>:: iterator st,ed;
     35     st=d[y].begin();
     36     ed=d[y].end();
     37     while(st!=ed)
     38     {
     39         d[x].insert(*st);
     40         st++;
     41     }
     42 }
     43 
     44 void extend(int x,int k)
     45 {
     46     int np=++tot;
     47     upd(np);d[np].insert(x);
     48     t[np].step=t[last].step+1;
     49     int now=last;
     50     while(now&&!t[now].son[k])
     51     {
     52         t[now].son[k]=np;
     53         now=t[now].pre;
     54     }
     55     if(!now) t[np].pre=1;
     56     else
     57     {
     58         int p=now,q=t[now].son[k];
     59         if(t[p].step+1==t[q].step) t[np].pre=q;
     60         else
     61         {
     62             int nq=++tot;
     63             upd(nq);
     64             memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
     65             get_d(nq,q);
     66             t[nq].pre=t[q].pre;
     67             t[q].pre=t[np].pre=nq;
     68             t[nq].step=t[p].step+1;
     69             while(now&&t[now].son[k]==q)
     70             {
     71                 t[now].son[k]=nq;
     72                 now=t[now].pre;
     73             }
     74         }
     75     }
     76     last=np;
     77 }
     78 
     79 int n,kk;
     80 void init()
     81 {
     82     scanf("%d%d",&n,&kk);
     83     t[++tot].step=0;
     84     upd(tot);
     85     int sl=0;
     86     for(int i=1;i<=n;i++)
     87     {
     88         scanf("%s",ss+1);
     89         l=strlen(ss+1);
     90         last=1;
     91         bg[i]=sl+1;
     92         for(int j=1;j<=l;j++)
     93         {
     94             int k=ss[j]-'a'+1;
     95             extend(i,k);
     96             s[++sl]=ss[j];
     97         }
     98     }
     99     bg[n+1]=sl+1;
    100 }
    101 
    102 struct hp
    103 {
    104     int x,y,next;
    105 }a[2*Maxn];int al=0;
    106 int first[2*Maxn];
    107 
    108 void ins(int x,int y)
    109 {
    110     a[++al].x=x;a[al].y=y;
    111     a[al].next=first[x];first[x]=al;
    112 }
    113 
    114 void dfs(int x)
    115 {
    116     for(int i=first[x];i;i=a[i].next)
    117     {
    118         dfs(a[i].y);
    119         get_d(x,a[i].y);
    120     }
    121 }
    122 
    123 int main()
    124 {
    125     init();
    126     memset(first,0,sizeof(first));
    127     for(int i=1;i<=tot;i++) ins(t[i].pre,i);
    128     dfs(1);
    129     bool ok=1;
    130     for(int i=1;i<=n;i++)
    131     {
    132         int now=1;
    133         LL ans=0;
    134         for(int j=bg[i];j<bg[i+1];j++)
    135         {
    136             int k=s[j]-'a'+1;
    137             now=t[now].son[k];
    138             while(now&&d[now].size()<kk) now=t[now].pre;
    139             if(!now) now=1;
    140             ans+=t[now].step;
    141         }
    142         if(!ok) printf(" ");
    143         else ok=0;
    144         printf("%lld",ans);
    145     }
    146     return 0;
    147 }
    [BZOJ 3473]

    2016-09-20 21:28:28

  • 相关阅读:
    阿里云服务器购买后的配置指南
    第一阶段总结
    RDD的checkpoint机制和键值对RDD数据分区
    广播变量与累加器
    Spark的监控
    Spark和MR的区别
    hadoop离线项目处理流程
    Flume(一)
    Sparkcore高级应用3
    SparkCore高级应用2(Spark on yarn)
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5806234.html
Copyright © 2020-2023  润新知