zoukankan      html  css  js  c++  java
  • 洛谷P4248 差异

    题意:求所有后缀两两之间的最长公共前缀的长度之和。

    解:这道题让我发现了一个奇妙的性质:所有后缀两两最长公共前缀长度之和 和 所有前缀两两最长公共后缀之和的值是相等的,但是每一组公共前/后缀是不同的。

    因为这道题要反建后缀自动机,我正建然后过了......

    两个串的最长公共后缀就是在fail树上的lca。

    所以反建后缀自动机,所有后缀就是主链。然后求这些两两的lca计算每个点作为lca被统计了多少次,树上DFS一遍就好了。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstring>
     4 
     5 typedef long long LL;
     6 const int N = 1000010;
     7 
     8 struct Edge {
     9     int nex, v;
    10 }edge[N]; int top;
    11 
    12 int tr[N][26], len[N], fail[N], cnt[N], tot = 1, last = 1;
    13 int e[N], siz[N];
    14 LL ans;
    15 char s[N];
    16 
    17 inline void add(int x, int y) {
    18     top++;
    19     edge[top].v = y;
    20     edge[top].nex = e[x];
    21     e[x] = top;
    22     return;
    23 }
    24 
    25 inline void insert(char c) {
    26     int f = c - 'a';
    27     int p = last, np = ++tot;
    28     last = np;
    29     len[np] = len[p] + 1;
    30     cnt[np] = 1;
    31     while(p && !tr[p][f]) {
    32         tr[p][f] = np;
    33         p = fail[p];
    34     }
    35     if(!p) {
    36         fail[np] = 1;
    37     }
    38     else {
    39         int Q = tr[p][f];
    40         if(len[Q] == len[p] + 1) {
    41             fail[np] = Q;
    42         }
    43         else {
    44             int nQ = ++tot;
    45             len[nQ] = len[p] + 1;
    46             fail[nQ] = fail[Q];
    47             fail[Q] = fail[np] = nQ;
    48             memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
    49             while(tr[p][f] == Q) {
    50                 tr[p][f] = nQ;
    51                 p = fail[p];
    52             }
    53         }
    54     }
    55     return;
    56 }
    57 
    58 inline void prework() {
    59     for(int i = 2; i <= tot; i++) {
    60         add(fail[i], i);
    61         //printf("add : %d %d 
    ", fail[i], i);
    62     }
    63     return;
    64 }
    65 
    66 void DFS(int x) {
    67     siz[x] = cnt[x];
    68     for(int i = e[x]; i; i = edge[i].nex) {
    69         int y = edge[i].v;
    70         DFS(y);
    71         if(x > 1) {
    72             ans += 1ll * siz[x] * siz[y] * len[x];
    73         }
    74         siz[x] += siz[y];
    75     }
    76     //printf("x = %d siz = %d 
    ", x, siz[x]);
    77     return;
    78 }
    79 
    80 int main() {
    81     LL sum = 0;
    82     scanf("%s", s);
    83     int n = strlen(s);
    84     for(int i = 0; i < n; i++) {
    85         insert(s[i]);
    86         sum += 1ll * (n - 1) * (i + 1);
    87     }
    88     prework();
    89     DFS(1);
    90     printf("%lld
    ", sum - 2 * ans);
    91     //printf("%lld - %lld 
    ", sum, 2 * ans);
    92     return 0;
    93 }
    AC代码(伪)
  • 相关阅读:
    JS 中 console 的用法
    C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
    C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo
    MEF框架使用总结
    webfunny前端监控开源项目
    我从Vue源码中学到的一些JS编程技巧
    nodejs 发送邮件demo
    从零开始手写Promise
    概率论要点
    行列式技巧
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10335692.html
Copyright © 2011-2022 走看看