zoukankan      html  css  js  c++  java
  • SPOJ NSUBSTR Substrings

    题目传送门

      传送站I

      传送站II

    题目大意

      给定一个字符串$S$,问对于任意整数$1leqslant xleqslant |S|$,长度为$x$的串最多出现了多少次。

      众所周知,我们可以用后缀自动机来求子串出现的次数。

      在parent树上,叶节点向根节点累加$cnt$。想想这样做的本质,就是求出了每个状态的$Right$集合的大小。

      根据parent指针的定义,子节点的Right集合是它的parent的Right集合的真子集,并且最短长度大于它的parent的最长长度。

      所以,每次修改区间$[l, r]$的最大值,可以看成直接修改$[1, r]$。因此,可以差分一下,每次单点修改,最后做一次后缀和。

      时间复杂度$O(|S|)$

    Code

     1 /**
     2  * SPOJ
     3  * Problem#NSUBSTR
     4  * Accepted
     5  * Time: 270ms
     6  * Memory: 89088k
     7  */
     8 #include <bits/stdc++.h>
     9 using namespace std;
    10 typedef bool boolean;
    11 #define smax(_a, _b) ((_a < _b) ? (_a = _b) : (0))
    12 
    13 const int N = 5e5 + 5, alpha = 26;
    14 
    15 typedef class TrieNode {
    16     public:
    17         int len, cnt;
    18 //        TrieNode* ch[26];
    19         map<int, TrieNode*> ch;
    20         TrieNode* fail;
    21 }TrieNode;
    22 
    23 TrieNode pool[N];
    24 TrieNode* sp[N];
    25 TrieNode* top = pool;
    26 
    27 TrieNode* newnode(int len) {
    28     top->len = len;
    29     return top++;
    30 }
    31 
    32 typedef class SuffixAutomaton {
    33     public:
    34         TrieNode* rt;
    35         TrieNode* last;
    36 
    37         SuffixAutomaton() {
    38             last = rt = newnode(0);
    39         }
    40 
    41         void extend(char x) {
    42             int c = x - 'a';
    43             TrieNode *f = last, *p = newnode(last->len + 1);
    44             while (f && !f->ch[c])
    45                 f->ch[c] = p, f = f->fail;
    46             if (!f)
    47                 p->fail = rt;
    48             else {
    49                 TrieNode* q = f->ch[c];
    50                 if (q->len == f->len + 1)
    51                     p->fail = q;
    52                 else {
    53                     TrieNode* nq = newnode(f->len + 1);
    54                     nq->fail = q->fail, q->fail = nq, p->fail = nq;
    55                     nq->ch = map<int, TrieNode*>(q->ch);
    56                     while (f && f->ch[c] == q)
    57                         f->ch[c] = nq, f = f->fail;
    58                 }
    59             }
    60             last = p, p->cnt = 1;
    61         }
    62 }SuffixAutomaton;
    63 
    64 int n;
    65 char str[N];
    66 int cnt[N], f[N];
    67 SuffixAutomaton sam;
    68 
    69 inline void init() {
    70     scanf("%s", str + 1);
    71     n = strlen(str + 1);
    72 }
    73 
    74 inline void solve() {
    75     for (int i = 1; i <= n; i++)
    76         sam.extend(str[i]);
    77 //    for (TrieNode* p = pool; p < top; p++)
    78 //        cerr << p - pool << " " << p->fail - pool << " " << p->len << " " << p->cnt << endl;
    79     for (TrieNode* p = pool + 1; p < top; p++)        cnt[p->len]++;
    80     for (int i = 2; i <= n; i++)        cnt[i] += cnt[i - 1];
    81     for (int i = 1; pool + i < top; i++)        sp[cnt[pool[i].len]--] = pool + i;
    82     for (int i = top - pool - 1; i; i--)    sp[i]->fail->cnt += sp[i]->cnt;
    83     for (int i = 1; pool + i < top; i++)    smax(f[sp[i]->len], sp[i]->cnt);
    84     for (int i = n; i > 1; i--)    smax(f[i - 1], f[i]);
    85     for (int i = 1; i <= n; i++)
    86         printf("%d
    ", f[i]);
    87 }
    88 
    89 int main() {
    90     init();
    91     solve();
    92     return 0;
    93 }
  • 相关阅读:
    Android微信九宫格图片展示控件
    ImageView设置rounded corner
    Android TitleBar推荐
    《Windows核心编程》目录索引
    《Windows内核分析》专题-索引目录
    wchar,char,string,wstring互转
    键盘过滤
    串口过滤
    Vmware中Linux 虚拟机与Windows物理机建立共享文件夹
    遍历某一进程模块
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8644833.html
Copyright © 2011-2022 走看看