zoukankan      html  css  js  c++  java
  • [bzoj4516][Sdoi2016]生成魔咒——后缀自动机

    Brief Description

    魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
    一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
    例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、
    [1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都
    需要求出,当前的魔咒串 S 共有多少种生成魔咒。

    Algorithm Design

    后缀自动机。每次加入一个新的节点的时候统计。

    Code

    #include <cstdio>
    #include <map>
    const int maxn = 100010;
    int n, m, tot = 1, last = 1;
    #define ll long long
    ll ans;
    int len[maxn << 1], fa[maxn << 1];
    std::map<int, int> ch[maxn << 1];
    int calc(int x) { return len[x] - len[fa[x]]; }
    void insert(int x) {
      int p = last, np = last = ++tot;
      len[np] = len[p] + 1;
      while (p && !ch[p][x])
        ch[p][x] = np, p = fa[p];
      if (!p)
        fa[np] = 1, ans += calc(np);
      else {
        int q = ch[p][x];
        if (len[p] + 1 == len[q])
          fa[np] = q, ans += calc(np);
        else {
          int nq = ++tot;
          len[nq] = len[p] + 1;
          ch[nq] = ch[q];
          fa[nq] = fa[q];
          ans += calc(nq) - calc(q);
          fa[q] = fa[np] = nq;
          ans += calc(np) + calc(q);
          while (p && ch[p][x] == q)
            ch[p][x] = nq, p = fa[p];
        }
      }
    }
    int main() {
      scanf("%d", &n);
      for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        insert(x);
        printf("%lld
    ", ans);
      }
    }
    
  • 相关阅读:
    洛谷 P1213 时钟 &&IOI 1994 The Clocks
    P1457 城堡 The Castle
    [USACO08OCT]牧场散步Pasture Walking
    洛谷 P1262 间谍网络
    [USACO09DEC]牛收费路径Cow Toll Paths
    1266: [AHOI2006]上学路线route
    1093: [ZJOI2007]最大半连通子图
    洛谷 P3797 妖梦斩木棒
    1821: [JSOI2010]Group 部落划分 Group
    2019中国产业互联网领袖峰会(上海)
  • 原文地址:https://www.cnblogs.com/gengchen/p/6550915.html
Copyright © 2011-2022 走看看