zoukankan      html  css  js  c++  java
  • 【AHOI 2013】差异

    Problem

    Description

    给定一个长度为 (n) 的字符串 (S),令 (T_i) 表示它从第 (i) 个字符开始的后缀。求

    (sum_{1leqslant i<jleqslant n}len(T_i)+len(T_j)-2 imes len(lcp(T_i,T_j)))

    其中,(len)(a) 表示字符串 (a) 的长度,(lcp)(a,b) 表示字符串 (a) 和字符串 (b) 的最长公共前缀。

    Input Format

    一行,一个字符串 (S)

    Output Format

    一行,一个整数,表示所求值。

    Sample

    Input

    cacao
    

    Output

    54
    

    Range

    (2leqslant nleqslant 5 imes 10^5) ,且均为小写字母。

    Algorithm

    后缀自动机

    Mentality

    转换成统计每个字符对答案的贡献。

    对于后缀自动机上的某个节点,便代表了某个等价类里的一堆连续子串,我们发现,这些子串中的字符产生贡献当且仅当两个后缀 (T_1, T_2) 一个经过当前节点,而另一个不经过。

    那么这些字符产生的贡献就是经过当前节点的后缀数乘上不经过的后缀数。

    Code

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    #define LL long long
    #define go(x, i, v) for (int i = hd[x], v = to[i]; i; v = to[i = nx[i]])
    LL read() {
      long long x = 0, w = 1;
      char ch = getchar();
      while (!isdigit(ch)) w = ch == '-' ? -1 : 1, ch = getchar();
      while (isdigit(ch)) {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
      }
      return x * w;
    }
    const int Max_n = 5e5 + 5, M = 26;
    int n;
    long long ans;
    int num[Max_n << 1], nu[Max_n << 1];
    char S[Max_n];
    namespace SAM {
    int las = 1, cnt = 1;
    struct node {
      int len, fa, ch[M];
    } k[Max_n << 1];
    void add(int c) {
      int p = las, np = las = ++cnt;
      k[np].len = k[p].len + 1, nu[np] = 1;
      for (; p && !k[p].ch[c]; p = k[p].fa) k[p].ch[c] = np;
      if (!p)
        k[np].fa = 1;
      else {
        int q = k[p].ch[c];
        if (k[q].len == k[p].len + 1)
          k[np].fa = q;
        else {
          int nq = ++cnt;
          k[nq] = k[q], k[nq].len = k[p].len + 1;
          k[q].fa = k[np].fa = nq;
          for (; p && k[p].ch[c] == q; p = k[p].fa) k[p].ch[c] = nq;
        }
      }
    }
    }  // namespace SAM
    using namespace SAM;
    bool cmp(int a, int b) { return k[a].len < k[b].len; }
    int main() {
      scanf("%s", S + 1);
      n = strlen(S + 1);
      for (int i = n; i >= 1; i--) add(S[i] - 'a');
      for (int i = 1; i <= cnt; i++) num[i] = i;
      sort(num + 1, num + cnt + 1, cmp);
      for (int i = cnt; i; i--) {
        int x = num[i];
        nu[k[x].fa] += nu[x];
        ans += 1ll * nu[x] * (n - nu[x]) * (k[x].len - k[k[x].fa].len);
      }
      cout << ans;
    }
    
  • 相关阅读:
    使用纯资源DLL文件实现多语言菜单、界面文字、Tooltips等[转]
    用VC++打造有多语言菜单的应用程序[转]
    VC2008以资源形式实现多语言版本[转]
    GetWindowRect与GetClientRect 的区别[转]
    MFC拆分窗口及它们之间的数据交换[转]
    【排序算法】(7)快速排序
    【排序算法】(4)归并排序
    【排序算法】(3)插入排序
    【排序算法】(8)希尔排序
    【排序算法】(2)冒泡排序
  • 原文地址:https://www.cnblogs.com/luoshuitianyi/p/11823284.html
Copyright © 2011-2022 走看看