• bzoj 2251


    第一道后缀数组

    后缀数组要维护三个数组:sa(suffix array), rk(rank)和ht(height)。

    含义分别是:

    sa[i]:将后缀按照字典序排序后,第i大的后缀的起始位置。

    rk[i]:起始位置为i的后缀的排名。

    ht[i]:起始位置为i的后缀与排名为rk[i]-1的后缀的最长公共前缀。

    对于任意一个字串,一定是某个后缀的前缀。

    然后从sa[1]开始,统计字串,每个后缀sa[i]的可能的字串的个数(不与前面统计的重复)是:n-sa[i]+1-ht[sa[i]]

    然后就这羊枚举子串,幷向后暴力统计个数,这样还能保证字典序是从小到大。

     1 /**************************************************************
     2     Problem: 2251
     3     User: idy002
     4     Language: C++
     5     Result: Accepted
     6     Time:240 ms
     7     Memory:892 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #define maxn 3010
    12  
    13 int n;
    14 int aa[maxn];
    15 int sa[2][maxn], rk[2][maxn], ht[maxn], vv[maxn], p;
    16 char str[maxn];
    17  
    18 void expand( int k, int sa[maxn], int rk[maxn], int tsa[maxn], int trk[maxn] ) {
    19     for( int i=1; i<=n; i++ ) vv[rk[sa[i]]]=i;
    20     for( int i=n; i>=1; i-- ) if( sa[i]>k ) tsa[vv[rk[sa[i]-k]]--]=sa[i]-k;
    21     for( int i=n-k+1; i<=n; i++ ) tsa[vv[rk[i]]--]=i;
    22     for( int i=1; i<=n; i++ ) trk[tsa[i]]=trk[tsa[i-1]]+(rk[tsa[i]]!=rk[tsa[i-1]]||rk[tsa[i]+k]!=rk[tsa[i-1]+k]);
    23 }
    24 void makeht() {
    25     int k=0;
    26     ht[sa[p][1]] = 0;
    27     for( int i=1; i<=n; i++ ) {
    28         if( rk[p][i]==1 ) continue;
    29         int j=sa[p][rk[p][i]-1];
    30         while( aa[i+k]==aa[j+k] ) k++;
    31         ht[i] = k;
    32         if( k>0 ) k--;
    33     }
    34 }
    35 void suffix() {
    36     p=0;
    37     for( int i=1; i<=n; i++ ) vv[aa[i]]++;
    38     for( int i=1; i<=2; i++ ) vv[i]+=vv[i-1];
    39     for( int i=n; i>=1; i-- ) sa[p][vv[aa[i]]--]=i;
    40     for( int i=1; i<=n; i++ ) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(aa[sa[p][i]]!=aa[sa[p][i-1]]);
    41     for( int k=1; k<n; k<<=1,p=1-p ) expand( k, sa[p], rk[p], sa[1-p], rk[1-p] );
    42     makeht();
    43 }
    44  
    45 int main() {
    46     scanf( "%d", &n );
    47     scanf( "%s", str+1 );
    48     for( int i=1; i<=n; i++ )
    49         aa[i] = str[i]-'0'+1;
    50     suffix();
    51     for( int i=1; i<=n; i++ ) {
    52         for( int t=sa[p][i]+ht[sa[p][i]]; t<=n; t++ ) {
    53             int cnt=1;
    54             for( int j=i+1; j<=n && ht[sa[p][j]]>=(t-sa[p][i]+1); j++,cnt++);
    55             if( cnt>1 )
    56                 printf( "%d
    ", cnt );
    57         }
    58     }
    59 }
    60 
    View Code
  • 相关阅读:
    自定义GridView分页控件
    ASP.NET中JSON的序列化和反序列化 C#的JSON数据格式转换方法
    C# 中 Struct 与 Class 的区别,以及两者的适用场合
    IEnumerable
    谈谈C#中的三个关键词new , virtual , override
    常见通信协议
    当base-package="controller.*"时,可见packageSearchPath为"classpath*:controller/*/**/*.class": 当base-package="controller.**"时,可见packageSearchPath为"classpath*:controller/**/**/*.class":
    DO,DTO和VO的使用
    mysql 字符
    mysql sql 分析
  • 原文地址:https://www.cnblogs.com/idy002/p/4344673.html
Copyright © 2020-2023  润新知