zoukankan      html  css  js  c++  java
  • 洛谷 P4248: bzoj 3238: [AHOI2013]差异

    题目传送门:洛谷 P4248

    题意简述:

    定义两个字符串 (S) 和 (T) 的差异 (operatorname{diff}(S,T)) 为这两个串的长度之和减去两倍的这两个串的最长公共前缀的长度。

    给定一个字符串,定义从第 (i) 个字符开始的后缀为 (Suf_i)。

    求 (sum_{1le i<jle n}operatorname{diff}(Suf_i,Suf_j))。

    题解:

    化简式子,原式等于

    [egin{align*}&left(sum_{1le i<jle n}i+j ight)-2 imessum_{1le i<jle n}operatorname{lcp}(Suf_i,Suf_j)\=& frac{n(n-1)(n+1)}{2}-2 imessum_{1le i<jle n}operatorname{lcp}(Suf_i,Suf_j)end{align*}]

    所以只要求出后半部分即可。

    建立字符串的后缀数组。

    考虑 Height 数组的贡献:Height 数组中 [2, n] 内的每一个区间都给答案贡献区间最小值。

    套路:每个区间的区间最小值之和,使用单调栈解决。

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 typedef long long LL;
     5 const int MN = 500005;
     6 
     7 int N;
     8 char str[MN];
     9 
    10 int M;
    11 int rk[MN], rk2[MN], SA[MN], SA2[MN];
    12 int buk[MN], cnt;
    13 int Height[MN];
    14 
    15 void GetHeight() {
    16     int k = 0;
    17     for (int i = 1; i <= N; ++i) {
    18         if (rk[i] == 1) { k = Height[1] = 0; continue; }
    19         if (k) --k;
    20         int j = SA[rk[i] - 1];
    21         while (i + k <= N && j + k <= N && str[i + k] == str[j + k]) ++k;
    22         Height[rk[i]] = k;
    23     }
    24 }
    25 
    26 void Rsort() {
    27     for (int i = 1; i <= M; ++i) buk[i] = 0;
    28     for (int i = 1; i <= N; ++i) ++buk[rk[i]];
    29     for (int i = 1; i <= M; ++i) buk[i] += buk[i - 1];
    30     for (int i = N; i >= 1; --i) SA[buk[rk[SA2[i]]]--] = SA2[i];
    31 }
    32 
    33 void GetSA() {
    34     M = 26;
    35     for (int i = 1; i <= N; ++i) rk[i] = str[i] - 'a' + 1, SA2[i] = i;
    36     Rsort();
    37     for (int j = 1; j < N; j <<= 1) {
    38         int P = 0;
    39         for (int i = N - j + 1; i <= N; ++i) SA2[++P] = i;
    40         for (int i = 1; i <= N; ++i) if (SA[i] > j) SA2[++P] = SA[i] - j;
    41         Rsort();
    42         rk2[SA[1]] = P = 1;
    43         for (int i = 2; i <= N; ++i) {
    44             if (rk[SA[i]] != rk[SA[i - 1]] || rk[SA[i] + j] != rk[SA[i - 1] + j]) ++P;
    45             rk2[SA[i]] = P;
    46         }
    47         for (int i = 1; i <= N; ++i) rk[i] = rk2[i];
    48         M = P;
    49         if (M == N) break;
    50     }
    51     GetHeight();
    52 }
    53 
    54 int st[MN], t;
    55 int L[MN], R[MN];
    56 
    57 int main() {
    58     scanf("%s", str + 1);
    59     N = strlen(str + 1);
    60     GetSA();
    61     st[t = 1] = 1;
    62     for (int i = 2; i <= N; ++i) {
    63         while (t && Height[st[t]] > Height[i]) R[st[t--]] = i;
    64         L[i] = st[t];
    65         st[++t] = i;
    66     } while (t) R[st[t--]] = N + 1;
    67     LL Ans = (LL)(N - 1) * N * (N + 1) / 2;
    68     for (int i = 2; i <= N; ++i)
    69         Ans -= 2ll * (R[i] - i) * (i - L[i]) * Height[i];
    70     printf("%lld
    ", Ans);
    71     return 0;
    72 }
  • 相关阅读:
    区块链基础语言(十二)——Go语言跳转语句
    区块链基础语言(十一)——Go语言循环语句
    区块链基础语言(十)——Go语言选择语句
    区块链基础语言(九)——Go语言运算符
    区块链技术语言(八)——Go语言常量
    区块链基础语言(七)——Go语言变量
    区块链基础语言(六)——Go语言数据类型
    区块链基础语言(五)——Go语言结构
    区块链基础语言(四)——Go语言工程管理
    人生苦短,我用 Python
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/10124064.html
Copyright © 2011-2022 走看看