混子的 后缀数组 刷题记录

洛谷P3809 【模板】后缀排序

  • 先来一道最水的模板题o(*≧▽≦)ツ┏━┓
  • sa[nmax]  sa[i]     排名为i的数的下标是多少
  • x[nmax]    x[i]       值,value,这个每次循环都要根据排名更新一遍
  • y[nmax]    y[i]       两次作为中间数组使用,第一次根据sa[i]更新第二关键字排名为i的数第一关键字的位置,第二次更新x[i](由于比较的时候用到原来x[i]的值,所以先用y[i]更新,最后把y[i]赋值给x[i])
  • qsort()函数   知道了每个数第二关键字的排名(y[i])和第一个关键字的值(x[i])求数的排名,用基数排序,结果在sa[i]里面
  • 每次循环完的状态: x[i] , sa[i] 已经求出
  • 最外层循环的 l :对应当前的sa[i]的l,在本次循环之后sa[i]指代的长度变为 2l
  • 所以 l<n (或者<=n/2) 
  • 好容易写错啊这个后缀数组。。。代码里是一些容易错的点
  • 代码:
     1 #include <bits/stdc++.h>
     2 #define nmax 1000010
     3 
     4 using namespace std;
     5 int c[nmax],rk[nmax],sa[nmax],x[nmax],y[nmax];
     6 //y[i]第二关键字排名为i的数第一关键字的位置
     7 
     8 char s[nmax];
     9 int n,k,m=200;
    10 
    11 void qsort(){
    12     for (int i=1; i<=m; i++) c[i]=0;
    13     for (int i=1; i<=n; i++) c[ x[i] ]++;
    14     for (int i=1; i<=m; i++) c[i]+=c[i-1];
    15     for (int i=n; i>=1; i--) sa[ c[ x[y[i]] ]-- ]=y[i];
    16 }
    17 
    18 int main(){
    19     scanf("%s",s+1);
    20     n=strlen(s+1);
    21     for (int i=1; i<=n; i++) x[i]=s[i];
    22     for (int i=1; i<=n; i++) y[i]=i;
    23     qsort();
    24     for (int l=1; l<n; l<<=1) { 
    25         int t=0;
    26         for (int i=n-l+1; i<=n; i++) y[++t]=i; 
    27         //有些数字是没有第一关键字的,有些数字的第二关键字不在sa[i]能覆盖的范围内
    28         for (int i=1; i<=n; i++) if(sa[i]>l) y[++t]=sa[i]-l;  //如果有第一关键字
    29         qsort();
    30         m=1;
    31         y[ sa[1] ]=m;
    32         for (int i=2; i<=n; i++) {
    33             //这里容易错,sa[i]指代的长度有2l,但是x指代的长度只有l,所以第二关键字也要比较
    34             if( x[sa[i]]==x[sa[i-1]] ) if( x[ sa[i]+l ]==x[sa[i-1]+l] ) { y[ sa[i] ]=m; continue; }
    35             y[ sa[i] ]=++m;
    36         }
    37         for (int i=1; i<=n; i++) x[i]=y[i];
    38     }
    39     for (int i=1; i<=n; i++) printf("%d ",sa[i]);
    40     return 0;
    41 }
    (<ゝω・)☆

 

POJ2774 Long Long Message

  • 题意:求两个串的最长公共子串
  • 在两个串中间加一个特殊字符平成一个串,然后在height里面找最大值就行了,注意判断一下是不是一个串里重复出现的字串
  • 代码:
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #define nmax 200010
     6 
     7 using namespace std;
     8 int x[nmax],y[nmax],sa[nmax],c[nmax],he[nmax],rk[nmax],a[nmax];
     9 char in[nmax];
    10 int n,m,ans,la,lb;
    11 
    12 inline void qsort(){
    13     for (int i=0; i<=m; i++) c[i]=0;
    14     for (int i=1; i<=n; i++) c[ x[i] ]++;
    15     for (int i=1; i<=m; i++) c[i]+=c[i-1];
    16     for (int i=n; i>=1; i--) sa[ c[ x[ y[i] ] ]-- ]=y[i];
    17 }
    18 
    19 inline void init(){
    20     ans=0;
    21     m=200;
    22     for (int i=1; i<=n; i++) y[i]=i;
    23     for (int i=1; i<=n; i++) he[i]=0;
    24 }
    25 
    26 inline void cheight(){
    27     for (int i=1; i<=n; i++) rk [ sa[i] ] = i;
    28     int cnt=0;  //cnt就是lca的长度拉
    29     for (int i=1; i<=n; i++) {
    30         if(cnt<0) cnt=0;
    31         int b = sa[ rk[i]-1 ];  //排在它前一个的那个串的下标
    32         while( a[ b+cnt ] == a[ i+cnt ] ) cnt++;
    33         he[ rk[i] ]=cnt;
    34         //更新答案注意不是一个串内的
    35         if( (i>la && b<=la)||(i<=la && b>la) ) ans=max(ans,cnt);
    36         cnt--;
    37     }
    38 }
    39 
    40 int main(){
    41     //freopen("owo.out","w",stdout);
    42     scanf("%s",in+1);
    43     la = strlen(in+1);
    44     scanf("%s",in+la+2);
    45     in[1+la]='X';  //中间放字符
    46     n=strlen(in+1);
    47     init();
    48     for (int i=1; i<=n; i++) x[i]=a[i]=in[i];
    49     qsort();
    50     for (int l=1; l<n; l<<=1) {  //sa部分
    51         int cnt=0;
    52         for (int i=n-l+1; i<=n; i++) y[++cnt]=i;
    53         for (int i=1; i<=n; i++) if(sa[i]>l) y[++cnt]=sa[i]-l;
    54         qsort();
    55         for (int i=1; i<=n; i++) y[i]=x[i];
    56         x[ sa[1] ]=m=1;
    57         for (int i=2; i<=n; i++) {
    58             if( ( y[ sa[i] ] != y[ sa[i-1] ] )||( y[ sa[i]+l ] != y[ sa[i-1]+l ] ) ) m++;  
    59             x[ sa[i] ]=m;
    60         }
    61     }
    62     cheight();
    63     printf("%d\n",ans); 
    64     return 0;
    65 }
    (❤ ω ❤)

     

posted @ 2019-09-29 17:41  连昵称都不能重复  阅读(144)  评论(0编辑  收藏  举报