• [tyvj1860]后缀数组


    题目链接:http://www.tyvj.cn/p/1860

    解题关键:模板题。贴一个代码详解

    http://www.cnblogs.com/staginner/archive/2012/02/02/2335600.html

    注意:一个字符串中的所有子串都必然是它的后缀的前缀

    da算法,必须保证字符串中每个字符的映射>=1

    注意点:sa从0~n-1,rank1数组和height数组从1-n

    height[1]恒为0

     1 #include<cstdlib>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<iostream>
     6 #include<cmath>
     7 using namespace std;
     8 const int N=200005;
     9 int wa[N],wb[N],wv[N],wc[N];
    10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}//比较两个字符串是否完全相同 
    11 void make_sa(int *r,int *sa,int n,int m){//最大值小于m 
    12     int i,j,p,*x=wa,*y=wb;//x,y是指针 
    13     for(i=0;i<m;i++) wc[i]=0;
    14     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
    15     for(i=1;i<m;i++) wc[i]+=wc[i-1];
    16     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;//基数排序
    17     for(j=1,p=1;p<n;j*=2,m=p){
    18         for(p=0,i=n-j;i<n;i++) y[p++]=i;
    19         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;//y是第二关键词的sa 
    20         for(i=0;i<n;i++) wv[i]=x[y[i]];
    21         for(i=0;i<m;i++) wc[i]=0;
    22         for(i=0;i<n;i++) wc[wv[i]]++;
    23         for(i=1;i<m;i++) wc[i]+=wc[i-1];
    24         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
    25         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;//x是rank数组,1 1 2 2 2 3 这种 
    26     }
    27     return;
    28 }
    29 int rank1[N],height[N],sa[N];//注意sa和rank的对应关系,sa的数值从0开始,rank的数值从1开始 
    30 void make_height(int *r,int *sa,int n){
    31     int i,j,k=0;
    32     for(i=1;i<=n;i++) rank1[sa[i]]=i;
    33     for(i=0;i<n;height[rank1[i++]]=k)
    34         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
    35     return;
    36 }
    37 //sa是名次所在位置,rank是位置所在名次
    38 int r[N<<1];
    39 int main() {
    40     ios::sync_with_stdio(0);
    41     int n=0;
    42     string s;
    43     cin>>s;
    44     for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n]=0;
    45     make_sa(r,sa,n+1,27);
    46     make_height(r,sa,n);
    47     for(int i=1;i<=n;i++) cout<<sa[i]+1<<" ";cout<<"
    ";//这里的1是逻辑上的首位 
    48     for(int i=1;i<=n;i++) cout<<height[i]<<" ";cout<<"
    ";
    49 }

     下面这种调用方式更无脑一些

     1 #include <cstdlib>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #include<iostream>
     6 #include<cstdlib>
     7 using namespace std;
     8 
     9 const int N = 200005;
    10 int wa[N],wb[N],wv[N],wc[N];
    11 
    12 bool cmp(int *r,int a,int b,int l){
    13     return r[a]==r[b]&&r[a+l]==r[b+l];
    14 }
    15 
    16 void make_sa(int *r,int *sa,int n,int m){//m是至多有多少个字符,up的意思
    17     int i,j,p,*x=wa,*y=wb;
    18     for(i=0;i<m;i++) wc[i]=0;
    19     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
    20     for(i=1;i<m;i++) wc[i]+=wc[i-1];
    21     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
    22     for(j=1,p=1;p<n;j*=2,m=p){
    23         for(p=0,i=n-j;i<n;i++) y[p++]=i;
    24         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
    25         for(i=0;i<n;i++) wv[i]=x[y[i]];
    26         for(i=0;i<m;i++) wc[i]=0;
    27         for(i=0;i<n;i++) wc[wv[i]]++;
    28         for(i=1;i<m;i++) wc[i]+=wc[i-1];
    29         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
    30         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++)
    31             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    32     }
    33     return;
    34 }
    35 
    36 int rank1[N],height[N],sa[N];//输出都是从1开始存的,rank从0开始,最后需要+1,读入从下标0
    37 void make_height(int *r,int *sa,int n){
    38     int i,j,k=0;
    39     for(i=1;i<=n;i++) rank1[sa[i]]=i;
    40     for(i=0;i<n;height[rank1[i++]]=k)
    41         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
    42     return;
    43 }
    44 //sa是名次所在位置,rank是位置所在名次
    45 int r[N];
    46 int main() {
    47     ios::sync_with_stdio(0);
    48     cin.tie(0);
    49     cout.tie(0);
    50     string s;
    51     cin>>s;
    52     for(int i=0;i<s.size();i++) r[i]=(int)s[i];
    53     int t=(int)s.size();
    54     r[t]=0;
    55     make_sa(r, sa,t+1,128);//注意+1,因为补0的原因
    56     make_height(r, sa, t);
    57     for(int i=1;i<=t;i++) cout<<sa[i]+1<<" ";
    58     cout<<"
    ";
    59     for(int i=1;i<=t;i++) cout<<height[i]<<" ";
    60     cout<<"
    ";
    61     return 0;
    62 }

    后缀数组练习

    poj2774 最长公共子串问题,将两个字符串接在一起解决。height数组就代表lcp(最长公共前缀)

     1 #include <cstdlib>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #include<iostream>
     6 #include<cstdlib>
     7 using namespace std;
     8 const int N=200005;
     9 int wa[N],wb[N],wv[N],wc[N],n,m;
    10 bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
    11 void make_sa(int *r,int *sa,int n,int m){
    12     int i,j,p,*x=wa,*y=wb;
    13     for(i=0;i<m;i++) wc[i]=0;
    14     for(i=0;i<n;i++) wc[x[i]=r[i]]++;
    15     for(i=1;i<m;i++) wc[i]+=wc[i-1];
    16     for(i=n-1;i>=0;i--) sa[--wc[x[i]]]=i;
    17     for(j=1,p=1;p<n;j*=2,m=p){
    18         for(p=0,i=n-j;i<n;i++) y[p++]=i;
    19         for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
    20         for(i=0;i<n;i++) wv[i]=x[y[i]];
    21         for(i=0;i<m;i++) wc[i]=0;
    22         for(i=0;i<n;i++) wc[wv[i]]++;
    23         for(i=1;i<m;i++) wc[i]+=wc[i-1];
    24         for(i=n-1;i>=0;i--) sa[--wc[wv[i]]]=y[i];
    25         for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    26     }
    27     return;
    28 }
    29 int rank1[N],height[N],sa[N];
    30 void make_height(int *r,int *sa,int n){
    31     int i,j,k=0;
    32     for(i=1;i<=n;i++) rank1[sa[i]]=i;
    33     for(i=0;i<n;height[rank1[i++]]=k)
    34         for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
    35     return;
    36 }
    37 
    38 int r[N<<1];
    39 int main() {
    40     ios::sync_with_stdio(0);
    41     string s,t;
    42     cin>>s>>t;
    43     int n=0;
    44     for(int i=0;i<s.size();i++) r[n++]=s[i]-'a'+1; r[n++]=27;int sl=n;
    45     for(int i=0;i<t.size();i++) r[n++]=t[i]-'a'+1; r[n]=0;
    46     make_sa(r, sa, n+1, 28);
    47     make_height(r, sa, n);
    48     int ans=0;
    49     for(int i=1;i<n;i++){
    50         if((sa[i]<sl)!=(sa[i+1]<sl)){
    51             ans=max(ans,height[i+1]);
    52         }
    53     }
    54     cout<<ans<<"
    ";
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    1654. Minimum Jumps to Reach Home
    1129. Shortest Path with Alternating Colors
    1766. Tree of Coprimes
    1368. Minimum Cost to Make at Least One Valid Path in a Grid
    LeetCode 841 钥匙与房间
    LeetCode 268 缺失数字
    LeetCode 136 只出现一次的数字
    LeetCode 461 汉明距离
    LeetCode 557 反转字符串中的单词 III
    LeetCode 392 判断子序列
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7341514.html
Copyright © 2020-2023  润新知