• [SPOJ-NSUBSTR]Substrings


    题目大意:
      给你一个字符串s,求出不同长度出现次数最多的字串的最大出现次数。

    思路:
      先对s构造后缀自动机,然后把s放进去匹配,每一个经过的结点表示一种长度的子串,用一个cnt记录能以每个状态表示的子串数量,然后按拓扑序DP。
      注意拓扑序并不等同于在SAM中插入的次序,因为用new_q替代q的操作会打乱顺序。(上一道题可能是因为数据弱被我卡过去了)
      然后我想到了DFS,以为从根结点开始得到的DFS序就是拓扑序,然而这样会忽略那些不是任何状态的后继状态,但是有link指针的状态(它们同样可以向上传递)。
      参考了网上的题解,发现常用的SAM拓扑排序方法很简单,直接按照每个状态到根结点的最长距离len排序即可。
      然而这样遍历每个状态肯定是连续的在一个数组中比较方便,然而我是用的指针(学陈立杰),于是又用数组模拟指针。
      然后还是WA。
      后来发现是指针改写成数组模拟的时候把pq打反了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 const int LEN=250001;
     5 class SuffixAutomaton {
     6     private:
     7         static const int SIGMA_SIZE=26;
     8         int cnt[LEN],len,sz;
     9         struct State {
    10             int link,go[SIGMA_SIZE];
    11             int len,cnt;
    12         };
    13         State s[LEN<<1];
    14         int newState(const int l) {
    15             sz++; 
    16             s[sz].link=NULL;
    17             memset(s[sz].go,0,sizeof s[sz].go);
    18             s[sz].len=l;
    19             s[sz].cnt=0;
    20             return sz;
    21         }
    22         int root,last;
    23         int top[LEN<<1];
    24         int idx(const char ch) {
    25             return ch-'a'; 
    26         }
    27         void extend(const char ch) {
    28             const int w=idx(ch);
    29             int p=last;
    30             int new_p=newState(s[p].len+1);
    31             while(p!=NULL&&s[p].go[w]==NULL) {
    32                 s[p].go[w]=new_p;
    33                 p=s[p].link;
    34             }
    35             if(p==NULL) {
    36                 s[new_p].link=root;
    37             } else {
    38                 int q=s[p].go[w];
    39                 if(s[q].len==s[p].len+1) {
    40                     s[new_p].link=q; 
    41                 } else {
    42                     int new_q=newState(s[p].len+1);
    43                     memcpy(s[new_q].go,s[q].go,sizeof s[q].go);
    44                     s[new_q].link=s[q].link;
    45                     s[new_p].link=s[q].link=new_q;
    46                     while(p!=NULL&&s[p].go[w]==q) {
    47                         s[p].go[w]=new_q;
    48                         p=s[p].link;
    49                     }
    50                 }
    51             }
    52             last=new_p;
    53         }
    54         void match(char ss[]) {
    55             int p=root;
    56             for(int i=0;i<len;i++) {
    57                 p=s[p].go[idx(ss[i])];
    58                 s[p].cnt++;
    59             }
    60         }
    61         int f[LEN];
    62     public:
    63         void build(char s[]) {
    64             len=strlen(s);
    65             root=last=newState(0);
    66             for(int i=0;i<len;i++) {
    67                 extend(s[i]);
    68             }
    69         }
    70         void query(char ss[]) {
    71             match(ss);
    72             for(int i=1;i<=sz;i++) cnt[s[i].len]++;
    73             for(int i=len;i;i--) cnt[i-1]+=cnt[i];
    74             for(int i=sz;i;i--) top[cnt[s[i].len]--]=i;
    75             for(int i=1;i<=sz;i++) {
    76                 if(s[top[i]].link!=NULL) {
    77                     s[s[top[i]].link].cnt+=s[top[i]].cnt;
    78                 }
    79             }
    80             for(int i=1;i<=sz;i++) {
    81                 f[s[top[i]].len]=std::max(f[s[top[i]].len],s[top[i]].cnt);
    82             }
    83             for(int i=len;i;i--) {
    84                 f[i]=std::max(f[i],f[i+1]);
    85             }
    86             for(int i=1;i<=len;i++) printf("%d
    ",f[i]);
    87         }
    88 };
    89 SuffixAutomaton sam;
    90 char s[LEN];
    91 int main() {
    92     scanf("%s",s);
    93     sam.build(s);
    94     sam.query(s);
    95     return 0;
    96 }
  • 相关阅读:
    Elasticsearch、Logstash和Kibana Windows环境搭建(一)
    20200820--1维数组 年龄与疾病(奥赛一本通P78 5)
    20200820--1维数组 数组逆序重放(奥赛一本通P77 4)
    20200820--一维数组:与指定数字相同的数的个数(奥赛一本通P75 1)
    20200819--金币 奥赛一本通P73 10 已讲
    20200818-数1的个数(奥赛一本通 P69 5)
    bits/stdc++.h
    数1的个数(奥赛一本通 P69 5)
    函数和方法的讲解
    20200817-与7无关的数(奥赛一本通 P68 4)
  • 原文地址:https://www.cnblogs.com/skylee03/p/7518750.html
Copyright © 2020-2023  润新知