zoukankan      html  css  js  c++  java
  • BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

    Description

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

    Input

    第一行两个整数nk
    接下来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,字符串只包含小写字母。

    Solution

    加分隔符建出后缀数组,考虑每个后缀的所有前缀,这样就能考虑到所有的子串了。

    对于每一个后缀,二分前缀的长度,

    然后在二分里面再通过二分左右端点加$ST$表确定$lcp$大于等于之前二分前缀长度的后缀排名区间,

    最后用主席树查询一下区间颜色个数是否超过k就行了。查询方法参照HH的项链主席树做法。

    话说字符串拼接完了长度是$2 imes 10^5$不是$10^5$……数组开小真是太真实了。

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #define N (200009)
      5 #define LL long long
      6 using namespace std;
      7 
      8 struct Sgt{int ls,rs,val;}Segt[N*18];
      9 int sgt_num,Root[N],a[N],Next[N];
     10 int n,m=125,c,k;
     11 int wa[N],wb[N],wt[N];
     12 int Rank[N],SA[N],Height[N];
     13 int ST[N][18],LOG2[N];
     14 int ID[N],id_num,End[N];
     15 LL Ans[N];
     16 char r[N],s[N];
     17 
     18 bool cmp(int *y,int a,int b,int k)
     19 {
     20     int arank1=y[a];
     21     int brank1=y[b];
     22     int arank2=a+k>=n?-1:y[a+k];
     23     int brank2=b+k>=n?-1:y[b+k];
     24     return arank1==brank1 && arank2==brank2;
     25 }
     26 
     27 void Build_SA()
     28 {
     29     int *x=wa,*y=wb;
     30     for (int i=0; i<m; ++i) wt[i]=0;
     31     for (int i=0; i<n; ++i) ++wt[x[i]=r[i]];
     32     for (int i=1; i<m; ++i) wt[i]+=wt[i-1];
     33     for (int i=n-1; i>=0; --i) SA[--wt[x[i]]]=i;
     34     
     35     for (int j=1; j<=n; j<<=1)
     36     {
     37         int p=0;
     38         for (int i=n-j; i<n; ++i) y[p++]=i;
     39         for (int i=0; i<n; ++i) if (SA[i]>=j) y[p++]=SA[i]-j;
     40         
     41         for (int i=0; i<m; ++i) wt[i]=0;
     42         for (int i=0; i<n; ++i) ++wt[x[y[i]]];
     43         for (int i=1; i<m; ++i) wt[i]+=wt[i-1];
     44         for (int i=n-1; i>=0; --i) SA[--wt[x[y[i]]]]=y[i];
     45         
     46         m=1; swap(x,y); x[SA[0]]=0;
     47         for (int i=1; i<n; ++i)
     48             x[SA[i]]=cmp(y,SA[i],SA[i-1],j)?m-1:m++;
     49         if (m>=n) break;
     50     }
     51 }
     52 
     53 void Build_Height()
     54 {
     55     for (int i=0; i<n; ++i) Rank[SA[i]]=i;
     56     int k=0;
     57     for (int i=0; i<n; ++i)
     58     {
     59         if (!Rank[i]) continue;
     60         if (k) --k;
     61         int j=SA[Rank[i]-1];
     62         while (r[i+k]==r[j+k]) ++k;
     63         Height[Rank[i]]=k;
     64     }
     65 }
     66 
     67 void Build_ST()
     68 {
     69     for (int i=2; i<=n; ++i) LOG2[i]=LOG2[i>>1]+1;
     70     for (int i=0; i<n; ++i) ST[i][0]=Height[i];
     71     for (int j=1; j<=18; ++j)
     72         for (int i=0; i+(1<<j)-1<n; ++i)
     73             ST[i][j]=min(ST[i][j-1],ST[i+(1<<j-1)][j-1]);
     74 }
     75 
     76 int Query(int l,int r)
     77 {
     78     int k=LOG2[r-l+1];
     79     return min(ST[l][k],ST[r-(1<<k)+1][k]);
     80 }
     81 
     82 int Update(int pre,int l,int r,int x)
     83 {
     84     int now=++sgt_num;
     85     Segt[now]=Segt[pre]; Segt[now].val++;
     86     if (l==r) return now;
     87     int mid=(l+r)>>1;
     88     if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
     89     else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
     90     return now;
     91 }
     92 
     93 int Query(int u,int v,int l,int r,int l1,int r1)
     94 {
     95     if (l>r1 || r<l1) return 0;
     96     if (l1<=l && r<=r1) return Segt[v].val-Segt[u].val;
     97     int mid=(l+r)>>1;
     98     return Query(Segt[u].ls,Segt[v].ls,l,mid,l1,r1)+Query(Segt[u].rs,Segt[v].rs,mid+1,r,l1,r1);
     99 }
    100 
    101 void Build_CT()
    102 {
    103     for (int i=1; i<=c; ++i) Next[i]=n;
    104     for (int i=n-1; i>=0; --i) a[i+1]=Next[ID[SA[i]]], Next[ID[SA[i]]]=i;
    105     for (int i=1; i<=n; ++i) Root[i]=Update(Root[i-1],0,n,a[i]);
    106 }
    107 
    108 bool check(int p,int lim)
    109 {
    110     int l,r,L,R;
    111     l=0,r=p-1,L=p;
    112     while (l<=r)
    113     {
    114         int mid=(l+r)>>1,lcp=Query(mid+1,p);
    115         if (lcp>=lim) L=mid, r=mid-1;
    116         else l=mid+1;
    117     }
    118     l=p+1,r=n-1,R=p;
    119     while (l<=r)
    120     {
    121         int mid=(l+r)>>1,lcp=Query(p+1,mid);
    122         if (lcp>=lim) R=mid, l=mid+1;
    123         else r=mid-1;
    124     }
    125     return Query(Root[L],Root[R+1],0,n,R+1,n)>=k;
    126 }
    127 
    128 int main()
    129 {
    130     scanf("%d%d",&c,&k);
    131     for (int i=1; i<=c; ++i)
    132     {
    133         scanf("%s",s);
    134         for (int j=0,l=strlen(s); j<l; ++j)
    135             ID[n]=i, r[n++]=s[j];
    136         End[i]=n; ID[n]=i, r[n++]='#';
    137     }
    138     Build_SA(); Build_Height();
    139     Build_ST(); Build_CT();
    140     for (int i=0; i<n; ++i)
    141     {
    142         if (r[SA[i]]=='#') continue;
    143         int l=1,r=End[ID[SA[i]]]-SA[i],ans=0;
    144         while (l<=r)
    145         {
    146             int mid=(l+r)>>1;
    147             if (check(i,mid)) ans=mid, l=mid+1;
    148             else r=mid-1;
    149         }
    150         Ans[ID[SA[i]]]+=ans;
    151     }
    152     for (int i=1; i<=c; ++i)
    153         printf("%lld ",Ans[i]);
    154 }
  • 相关阅读:
    Python 接口测试之处理转义字符的参数和编码问题
    使用Postman工具做接口测试(三)——断言与参数提取
    Django 单元测试笔记
    django 发布会签到系统web开发
    Django自动化测试平台项目案例
    Cypress学习笔记6——Debugging调试代码
    Cypress学习笔记5——官方示例
    Cypress学习笔记4——编写第二个测试脚本(登录案例)
    Cypress学习笔记3——编写第一个测试脚本
    Cypress学习笔记2——Windows环境下安装Cypress
  • 原文地址:https://www.cnblogs.com/refun/p/10410968.html
Copyright © 2011-2022 走看看