• [SPOJ8222]NSUBSTR


    题目链接:http://www.spoj.com/problems/NSUBSTR/

    这道题在clj的ppt里面有讲到。

    对于每一个状态s,可以只考虑它表示的串里的的最长串,这样它的出现次数就是$|right(s)|$。最后用每一个f[len]去更新f[len-1]的答案就好了。

    我们来看一看这样做的正确性。如果一个长度为len的串出现了f[len]次,明显其包含在内的长度len-1的串也出现了f[len]次。如果len-1的串不仅被包含在len的串中,明显其$|right(s)|$会更大,即不和len的串在一个状态中,会被另一个更大的$|right(x)|$所更新。于是每一种长度的f值都会被直接计算或更新掉,保证了答案的最优性。

    那么问题来了,如何求一个状态s的$|right(s)|$呢?直接观察parent树以及回顾SAM的性质就会发现,一个状态的right集合是其孩子right集合的并集,证明显然。于是我们从叶子节点开始,按拓扑序套路往上更新一下就可以了,叶子节点也就是主链上的节点,串从第一个字符开始,显然$|right(s)|=1$。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int sz=0,la,rt;
     6 int ch[500010][26],l[500010],fa[500010];
     7 void Extend(int c){
     8     int end=++sz,tmp=la;
     9     l[end]=l[tmp]+1;
    10     while(tmp&&!ch[tmp][c]){
    11         ch[tmp][c]=end;
    12         tmp=fa[tmp];
    13     }
    14     if(!tmp) fa[end]=rt;
    15     else{
    16         int ne=ch[tmp][c];
    17         if(l[ne]==l[tmp]+1) fa[end]=ne;
    18         else{
    19             int np=++sz;
    20             memcpy(ch[np],ch[ne],sizeof(ch[ne]));
    21             fa[np]=fa[ne];
    22             l[np]=l[tmp]+1;
    23             fa[ne]=fa[end]=np;
    24             while(tmp&&ch[tmp][c]==ne){
    25                 ch[tmp][c]=np;
    26                 tmp=fa[tmp];
    27             }
    28         }
    29     }
    30     la=end;
    31 }
    32 char s[250010];
    33 int r[500010],c[500010],a[500010],f[500010];
    34 int main(){
    35     rt=la=++sz;
    36     scanf("%s",s+1);
    37     int len=strlen(s+1);
    38     for(int i=1;i<=len;i++){
    39         r[sz+1]=1;
    40         Extend(s[i]-'a');
    41     }
    42     for(int i=1;i<=sz;i++) c[l[i]]++;
    43     for(int i=1;i<=len;i++) c[i]+=c[i-1];
    44     for(int i=1;i<=sz;i++) a[c[l[i]]--]=i;
    45     for(int i=sz;i>=1;i--) r[fa[a[i]]]+=r[a[i]];
    46     for(int i=1;i<=sz;i++) f[l[i]]=max(f[l[i]],r[i]);
    47     for(int i=len;i>=1;i--) f[i]=max(f[i],f[i+1]);
    48     for(int i=1;i<=len;i++) printf("%d
    ",f[i]);
    49     return 0;
    50 }
  • 相关阅读:
    安卓天天练练(三)常用组件Toast
    安卓天天练练(二)相对布局和帧布局
    javascript表单操作
    JavaScript replace() 方法
    android基础(一)
    四大类NoSQL数据库
    php基础八(cookie)
    php基础(七)文件
    php基础(六)Include
    php基础(五)日期
  • 原文地址:https://www.cnblogs.com/halfrot/p/7452428.html
Copyright © 2020-2023  润新知