zoukankan      html  css  js  c++  java
  • SPOJ NSUBSTR

    NSUBSTR - Substrings

    题意:

      给一个字符串S,求长度为x的所有子串中,这些子串其中一个串的出现次数最多,求这个值。x=1,2,3....n

    分析:

      后缀自动机。

      right集合表示当前状态在出现在其他的位置。len为当前状态的最大的串。parent树中,父节点的right包含子节点,所有对子节点拓扑即可求出所有点的right。

      当前节点的最大串为len,那么这个串的出现次数就是|right|,right集合的大小,更新出每个长度的最多出现次数。当然小于len的串也可以出现这些次,所有最后用ans[i+1]更新ans[i]即可。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 
     5 inline int read() {
     6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
     7     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
     8 }
     9 
    10 const int N = 250010;
    11 
    12 struct Suffix_Automaton{
    13     int Index, Last, fa[N<<1], trans[N<<1][26], len[N<<1];
    14     int du[N<<1],q[N<<1],ans[N],Right[N<<1],L,R;
    15     char s[N];
    16     
    17     void extend(int c) {
    18         int P = Last, NP = ++Index;
    19         len[NP] = len[P] + 1;
    20         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
    21         if (!P) fa[NP] = 1;
    22         else {
    23             int Q = trans[P][c];
    24             if (len[P] + 1 == len[Q]) fa[NP] = Q;
    25             else {
    26                 int NQ = ++Index;
    27                 fa[NQ] = fa[Q];
    28                 len[NQ] = len[P] + 1;
    29                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
    30                 fa[Q] = NQ;
    31                 fa[NP] = NQ;
    32                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
    33             }
    34         }
    35         Last = NP;
    36     }
    37     void solve() {
    38         scanf("%s",s);
    39         
    40         Index = 0;
    41         Last = ++Index;
    42         int n = strlen(s);
    43         for (int i=0; i<n; ++i) extend(s[i] - 'a');
    44         
    45         for (int i=0,p=1; i<n; ++i) p=trans[p][s[i]-'a'], Right[p]++; // 将S(1~i)的点设为1,因为这个点的R的状态只能是1,并且parent树上没有子节点,注意字符串从0开始 
    46         L = 1,R = 0;
    47         for (int i=1; i<=Index; ++i) du[fa[i]] ++;
    48         for (int i=1; i<=Index; ++i) 
    49             if (!du[i]) q[++R] = i;
    50         while (L <= R) { // 拓扑 
    51             int u = q[L++];
    52             Right[fa[u]] += Right[u];
    53             du[fa[u]] --;
    54             if (!du[fa[u]]) q[++R] = fa[u];
    55         }
    56         for (int i=1; i<=Index; ++i) 
    57             ans[len[i]] = max(ans[len[i]], Right[i]);
    58         for (int i=n-1; i>=0; --i) 
    59             ans[i] = max(ans[i], ans[i+1]);
    60         for (int i=1; i<=n; ++i) printf("%d
    ",ans[i]);
    61     }
    62 }sam;
    63 
    64 int main() {
    65     sam.solve();
    66     return 0;
    67 }
  • 相关阅读:
    【题解】直线交点数
    【题解】[TJOI2010] 阅读理解
    清北学堂 2020 国庆J2考前综合强化 Day7
    清北学堂 2020 国庆J2考前综合强化 Day6
    清北学堂 2020 国庆J2考前综合强化 Day5
    清北学堂 2020 国庆J2考前综合强化 Day4
    清北学堂 2020 国庆J2考前综合强化 Day3
    test
    清北学堂 2020 国庆J2考前综合强化 Day2
    清北学堂 2020 国庆J2考前综合强化 Day1
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9334678.html
Copyright © 2011-2022 走看看