• 后缀数组题目


    hdu 3948

      1 /*
      2 题意:给你一个串,求该串的不同子回文串的个数;
      3 
      4 分析:首先我们想一下一个比较简单的问,求一个串的不同子串的个数
      5 显然每个子串都是一个后缀的前缀,那么只要按照SA[]统计该后缀i的前缀
      6 有那些是出现过的,也就是ans+=len[该后缀长]-height[i];
      7 
      8 
      9 同样的道理,我们先统计出以i为中心的回文串到最右边的距离,然后
     10 再统计不同回文串的个数,即减去相同回文串的个数,但是两者还是有区别的
     11 其次,为了统一奇偶的差别,我们构造出另一个字符串,
     12 s1=aabaa  -> s=$#a#a#b#a#a#  (可以参看本博客前前篇文章MANACHER) 
     13 首先我用MANACHER的预处理出以s[i]为中心的回文串到最右边的距离记录在lc[i];
     14 当然可以直接用后缀数组的方法求出(将反串加在原串后面,然后询问后缀i和后缀2*n-i的LCP,但要分奇偶)
     15 
     16 统计不同子串个数和统计不同回文串的个数的区别
     17 看样例:aabaa
     18 
     19 
     20 构造的串:$#a#a#b#a#a#
     21 后缀  lc[i]        回文串的个数     
     22 11    1    #            1
     23 9     3    #a#           3        
     24 7     1    #a#a#        1     
     25 1     1    #a#a#b#a#a#    1        
     26 3     3    #a#b#a#a#    3    & 
     27 5     1    #b#a#a#        1
     28                     
     29 0     1    $#a#a#b#a#a#    1
     30 10    2    a#            2
     31 8     2    a#a#        2
     32 2     2    a#a#b#a#a#    2
     33 4     2    a#b#a#a#        2
     34 6     6    b#a#a#        6
     35 
     36 先不考虑加入#后产生的回文串,
     37 在统计后缀3中包含的回文串时,会把#a,和#a#统计进去,但我们发现在统计后缀9时#a,#a#就已经被统计了
     38 也就是说统计后缀i中已经被统计过的回文串的个数,不一定只是后缀i-1中的回文,还有可能是更前面的,
     39 所以我们在遍历的过程中设置一个标记tmp,表示以字符i为中点能延伸的最长距离,而不是该串在原串中能延伸的距离
     40 
     41 至于加入#后多出了的回文串,可以发现不管是lc[]还是height[]长度都是延伸到#位置的也就是相减后/2就是原串的个数
     42 还有加进了#最后答案要减去1; 
     43  
     44 */
     45 #include<cstdio>
     46 #include<cstring>
     47 #include<cstdlib>
     48 #include<iostream>
     49 #include<algorithm>
     50 #include<cmath>
     51 #include<vector>
     52 using namespace std;
     53 typedef long long LL;
     54 const int N=200000+10;
     55 char s[N],s1[N];
     56 struct SuffixArray{
     57     int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y;
     58     int n,height[N],m;
     59     void sort(){
     60         for (int i=0;i<m;i++) c[i]=0;
     61         for (int i=0;i<n;i++) c[x[i]]++;
     62         for (int i=0;i<m;i++) c[i+1]+=c[i];
     63         for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i];
     64     }
     65     void build_sa(char *s){
     66         n=strlen(s); m=256;
     67         x=a1; y=a2; x[n]=y[n]=-1;
     68         for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i;
     69         sort();
     70         for (int k=1;k<=n;k<<=1){
     71             int p=0;
     72             for (int i=n-k;i<n;i++) sa[p++]=i;
     73             for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k;
     74             sort();
     75             p=0; swap(x,y);
     76             x[SA[0]]=0;
     77             for (int i=1;i<n;i++){
     78                 if ( y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++;
     79                 x[SA[i]]=p;
     80             }
     81             if (p+1==n) break;
     82             m=p+1;
     83         }
     84         rank=x; getHeight(s);
     85     }
     86     void getHeight(char *s){
     87         int k=0;
     88         for (int i=0;i<n;i++){
     89             if (k) k--;
     90             if (rank[i]==0) continue;
     91             int j=SA[ rank[i]-1 ];
     92             while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
     93             height[rank[i]]=k;
     94         }
     95         height[n]=0;
     96     }
     97 }H;
     98 int lc[N*2];
     99 int lx[N],ly[N];
    100 void init(char *s1){
    101     int c=0;
    102     int n=strlen(s1);
    103     s[c++]='$';s[c++]='#';
    104     for (int i=0;s1[i];i++){
    105         s[c++]=s1[i];
    106         s[c++]='#';
    107     }s[c]='';
    108     lc[0]=1;lc[1]=1;
    109     int k=1;
    110     for (int i=2;i<c;i++){
    111         int p=k+lc[k]-1;
    112         if (i>=p){
    113             int j=0;
    114             while (i-j>=0 && i+j<c && s[i-j]==s[i+j]) j++;
    115             lc[i]=j; k=i;
    116         }else {
    117             int j=2*k-i;
    118             if (i+lc[j]-1<p) lc[i]=lc[j];
    119             else {
    120                 int d=p-i+1;
    121                 while (i-d>=0 && i+d<c && s[i-d]==s[i+d]) d++;
    122                 lc[i]=d; k=i;
    123             } 
    124         }
    125     }
    126 
    127 }
    128 void solve(){
    129     int n=strlen(s);
    130     int ret=lc[H.SA[0]];
    131     int tmp=lc[H.SA[0]];
    132 //    cout<<s<<endl;
    133 
    134 //    cout<<H.SA[0]<<"    "<<lc[H.SA[0]]<<"    "<<s+H.SA[0]<<endl;
    135     for (int i=1;i<n;i++){
    136         int t=H.SA[i];
    137 //        cout<<H.SA[i]<<"    "<<lc[H.SA[i]]<<"    "<<s+H.SA[i]<<endl;
    138         ret+=max(0,(lc[t]-min(H.height[i],tmp))/2);//tmp表示以字符s[H.SA[i-1]]为中心已经被统计过的回文串的个数 
    139         if (lc[t]>=tmp) tmp=lc[t];
    140         else {
    141             tmp=min(tmp,H.height[i]);//从上一个传递到当前; 
    142             if (lc[t]>tmp) tmp=lc[t];//如果该后缀本身的回文个数更多久更新; 
    143         }
    144     }
    145     printf("%d
    ",ret-1);
    146 }
    147 int main(){
    148     int T,cas=0;
    149     scanf("%d",&T);
    150     while (T--){
    151         scanf("%s",s1);
    152         init(s1);
    153         H.build_sa(s);
    154         printf("Case #%d: ",++cas);
    155         solve();
    156     }
    157     return 0;
    158 }
    159 /*
    160 6 
    161 abba
    162 baab
    163 aabaa
    164 aaaa
    165 abab
    166 abcd
    167 
    168 
    169 */

    hdu 3518

      1 /*
      2 题意:统计一个字符串里不错至少2次且不覆盖的子串的个数
      3 
      4 后缀数组求出height后,枚举子串的长度L,利用L对height分组
      5 对于同一组里的后缀,如果在组里最小后缀和最大后缀的差大于L就说明至少有俩个长度为L串
      6 且不覆盖的出现,所以ans++;
      7 
      8 为什么这样不会重复统计,假设长度为L的字串s1是满足要求的串 
      9 让我们看一下长度为L的子串s1是如何被统计进去的,
     10 首先我们知道所有前缀是s1的后缀在SA[]数组里将连续出现,而且相邻的height[]>=L;
     11 也就是说只要其中俩个后缀的距离大于等于L就说明他们不重叠;
     12 所以串s1只会被统计一次;
     13 时间复杂度是o(n^2); 
     14  
     15 */
     16 #include<cstdio>
     17 #include<cstdlib>
     18 #include<cstring>
     19 #include<iostream>
     20 #include<algorithm>
     21 #include<vector>
     22 using namespace std;
     23 const int N=1000+10;
     24 struct SuffixArray{
     25     int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y;
     26     int n,height[N],m;
     27     void sort(){
     28         for (int i=0;i<m;i++) c[i]=0;
     29         for (int i=0;i<n;i++) c[x[i]]++;
     30         for (int i=0;i<m;i++) c[i+1]+=c[i];
     31         for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i];
     32     }
     33     void build_sa(char *s){
     34         n=strlen(s); m=256;
     35         x=a1;y=a2; x[n]=y[n]=-1;
     36         for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i;
     37         sort();
     38         for (int k=1;k<=n;k<<=1){
     39             int p=0;
     40             for (int i=n-k;i<n;i++) sa[p++]=i;
     41             for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k;
     42             sort();
     43             p=0; swap(x,y);
     44             x[SA[0]]=0;
     45             for (int i=1;i<n;i++){
     46                 if (y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++;
     47                 x[SA[i]]=p;
     48             }
     49             if (p+1==n) break;
     50             m=p+1;
     51         }
     52         rank=x;getHeight(s);
     53     }
     54     void getHeight(char *s){
     55         int k=0;
     56         for (int i=0;i<n;i++){
     57             if (k) k--;
     58             if (rank[i]==0) continue;
     59             int j=SA[ rank[i]-1 ];
     60             while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
     61             height[ rank[i] ]=k;
     62         }
     63         height[n]=0;
     64     }
     65 }H;
     66 char s[N];
     67 vector<int > g;
     68 void solve(){
     69     int ret=0;
     70     int n=strlen(s);
     71 /*    cout<<">.<"<<endl;
     72     for (int i=0;i<n;i++) cout<<H.SA[i]<<" ";cout<<endl;
     73     for (int i=0;i<n;i++) cout<<H.rank[i]<<" ";cout<<endl;
     74     for (int i=1;i<n;i++)cout<<H.height[i]<<" ";cout<<endl;
     75     cout<<">.<"<<endl;
     76 */    for (int i=n/2;i>=1;i--){
     77         g.clear();
     78         for (int j=1;j<=n;j++){
     79             if (H.height[j]>=i){
     80                 g.push_back(H.SA[j-1]);
     81             }else {
     82                 g.push_back(H.SA[j-1]);
     83                 sort(g.begin(),g.end());
     84                 int sz=g.size();
     85                 if (sz>1 && g[sz-1]-g[0]>=i) ret++;
     86                 g.clear();
     87             }
     88         }
     89         
     90     }
     91     printf("%d
    ",ret);
     92 }
     93 int main(){
     94     while (~scanf("%s",&s)){
     95         if (s[0]=='#') break;
     96         H.build_sa(s);
     97         solve();
     98     }
     99     return 0;
    100 }
    101 /*
    102 aaaa
    103 ababcabb
    104 aaaaaa
    105 #
    106 
    107 */

    hdu 4416

      1 /*
      2 题意:求出现在s串中,但不出现在其他n个串中的字串个数;
      3 
      4 类似统计求一个串中不同的子串个数;
      5  
      6 我的做法是,先链接这些串,定义起点在s中的后缀叫目标后缀;
      7 求从前往后,从后往前扫两边,求出每一个目标后缀在SA[]数组中前后
      8 最近的非目标后缀和其的LCP,Lx[]中保存的是两个中的较大值;
      9 因为有可能多个目标后缀在SA[]数组中是连续的,所以还要减去其中一部分
     10 比如
     11 2 bab 
     12 0 babab
     13 1 babac
     14 3 babd
     15 0,1都是目标后缀,2,3都是非目标后缀,那么0,1后缀的非法子串是bab
     16 有因为0,1后缀相邻,要减去(height[]-lx[]); 
     17 所以在统计的时候baba才只被统计一次,
     18  
     19 那么剩下的就是要求的串的个数, 
     20 */
     21 #include<cstdio>
     22 #include<cstring>
     23 #include<iostream>
     24 #include<algorithm>
     25 #include<cmath>
     26 #include<cstdlib>
     27 #include<vector>
     28 using namespace std;
     29 typedef long long LL;
     30 const int N=300000+10;
     31 struct SuffixArray{
     32     int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y;
     33     int n,height[N],m;
     34     void sort(){
     35         for (int i=0;i<m;i++) c[i]=0;
     36         for (int i=0;i<n;i++) c[x[i]]++;
     37         for (int i=0;i<m;i++) c[i+1]+=c[i];
     38         for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i];
     39     }
     40     void build_sa(char *s){
     41         n=strlen(s); m=256;
     42         x=a1; y=a2; x[n]=y[n]=-1;
     43         for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i;
     44         sort();
     45         for (int k=1;k<=n;k<<=1){
     46             int p=0;
     47             for (int i=n-k;i<n;i++) sa[p++]=i;
     48             for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k;
     49             sort();
     50             p=0; swap(x,y);
     51             x[SA[0]]=0;
     52             for (int i=1;i<n;i++){
     53                 if ( y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++;
     54                 x[SA[i]]=p;
     55             }
     56             if (p+1==n) break;
     57             m=p+1;
     58         }
     59         rank=x; getHeight(s);
     60     }
     61     void getHeight(char *s){
     62         int k=0;
     63         for (int i=0;i<n;i++){
     64             if (k) k--;
     65             if (rank[i]==0) continue;
     66             int j=SA[ rank[i]-1 ];
     67             while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
     68             height[rank[i]]=k;
     69         }
     70         height[n]=0;
     71     }
     72 }H;
     73 char s[N],tmps[N];
     74 int L;
     75 void read(){
     76     int n;scanf("%d",&n);
     77     scanf("%s",s);
     78     L=strlen(s);
     79     int le=strlen(s); s[le]='$';s[++le]=''; 
     80     for (int i=0;i<n;i++){
     81         scanf("%s",tmps);
     82         int l=strlen(tmps);
     83         strcpy(s+le,tmps);
     84         le+=l;
     85         s[le]='#'; s[++le]='';
     86     }s[le]='{';s[le+1]='';
     87     //cout<<s<<endl;
     88 }
     89 int lx[N];
     90 
     91 void solve(){
     92     int n=strlen(s);
     93     int tmp=H.height[1];
     94     for (int i=0;i<L;i++) lx[i]=0;
     95     for (int i=1;i<n-1;i++){
     96         if (H.SA[i]<L){
     97             lx[H.SA[i]]=tmp;
     98             tmp=min(tmp,H.height[i+1]);
     99         }else {
    100             tmp=H.height[i+1];
    101         }    
    102     }
    103     tmp=H.height[n-1];
    104     for (int i=n-2;i>0;i--){
    105         if (H.SA[i]<L){
    106             if (lx[H.SA[i]]<tmp) lx[H.SA[i]]=tmp;
    107             tmp=min(tmp,H.height[i]);
    108         }else {
    109             tmp=H.height[i];
    110         }
    111     }
    112     LL ret=0;
    113     
    114     for (int i=1;i<n;i++){
    115         if (H.SA[i]<L){
    116             ret+=L-H.SA[i]-lx[H.SA[i]];
    117             if (H.SA[i-1]<L){
    118                 if (H.height[i]>lx[H.SA[i]]) ret-=H.height[i]-lx[H.SA[i]];
    119             }
    120         }
    121     }
    122     printf("%I64d
    ",ret);
    123 }
    124 int main(){
    125     int T,cas=0;scanf("%d",&T);
    126     while (T--){
    127         read();
    128         H.build_sa(s);
    129         printf("Case %d: ",++cas);
    130         solve();
    131     }
    132     return 0;
    133 }
  • 相关阅读:
    法瑞意游记+攻略 一(巴黎 凡尔赛、荣军院,十二月二十六)
    [转]Exchange Server 2013部署系列之一:部署环境介绍
    [转]在Windows server 2012上部署DPM 2012 SP1 RTM之安装配置
    DinnerNow案例分析
    [转]DPM2012系列之六:在Win7上安装DPM远程管理控制台
    Windows Phone Dev Center Develop
    [转]DPM2012系列之十:备份exchange2010数据库
    [转]DPM2012系列之五:开启最终用户恢复功能
    Windows Phone Dev Center How do I join?
    [转]DPM2012系列之三:浅谈硬件需求
  • 原文地址:https://www.cnblogs.com/Rlemon/p/3170586.html
Copyright © 2020-2023  润新知