zoukankan      html  css  js  c++  java
  • bzoj3238 [Ahoi2013]差异

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3238

    题目:

    3238: [Ahoi2013]差异

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 3367  Solved: 1532
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个字符串S

    Output

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

    Sample Input

    cacao

    Sample Output


    54

    HINT

    2<=N<=500000,S由小写英文字母组成

    思路:

      很明显前面的len[i]+len[j]是不变的,所以可以直接求出,对于后面的有俩种做法:

      后缀自动机做法:

       我们知道沿parent树往上走是不断取后缀,也就是不断删首字母。

       所以如果把字符串反转,然后沿parent树往上走则是对前缀不断取前缀的过程,也就是不断删尾字母。

       这时parent树就成lcp树,树上每个状态都是一些子串的lcp,所以树dp一下即可。

       这个树dp部分有点巧妙,学习别人的,要我写会写成dfs的形式。

    sam做法:

     1 /**************************************************************
     2     Problem: 3238
     3     User: weeping
     4     Language: C++
     5     Result: Accepted
     6     Time:3356 ms
     7     Memory:122876 kb
     8 ****************************************************************/
     9  
    10 #include <bits/stdc++.h>
    11  
    12 using namespace std;
    13  
    14 struct SAM
    15 {
    16     static const int MAXN = 500002<<1;//大小为字符串长度两倍
    17     static const int LetterSize = 26;
    18  
    19     int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
    20     int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
    21  
    22     void init( void)
    23     {
    24         last = tot = 1;
    25         len[1] = 0;
    26         memset(ch,0,sizeof ch);
    27         memset(fa,0,sizeof fa);
    28         memset(cnt,0,sizeof cnt);
    29     }
    30  
    31     void add( int x)
    32     {
    33         int p = last, np = last = ++tot;
    34         len[np] = len[p] + 1, cnt[last] = 1;
    35         while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
    36         if( p == 0)
    37             fa[np] = 1;
    38         else
    39         {
    40             int q = ch[p][x];
    41             if( len[q] == len[p] + 1)
    42                 fa[np] = q;
    43             else
    44             {
    45                 int nq = ++tot;
    46                 memcpy( ch[nq], ch[q], sizeof ch[q]);
    47                 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
    48                 while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
    49             }
    50         }
    51     }
    52  
    53     void toposort( void)
    54     {
    55         for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
    56         for(int i = 1; i <= tot; i++)   sum[len[i]]++;
    57         for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
    58         for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
    59     }
    60  
    61     void work(void)
    62     {
    63         toposort();
    64         long long ans=1LL*len[last]*(len[last]+1)*(len[last]-1)/2;
    65         for(int i=tot;i;i--)
    66             ans-=2LL*cnt[fa[tp[i]]]*len[fa[tp[i]]]*cnt[tp[i]],cnt[fa[tp[i]]]+=cnt[tp[i]];
    67         printf("%lld
    ",ans);
    68     }
    69 } sam;
    70  
    71 char sa[500005];
    72  
    73 int main( void)
    74 {
    75     scanf("%s",sa);
    76     sam.init();
    77     for(int i=strlen(sa)-1;i>-1;i--)   sam.add(sa[i]-'a');
    78     sam.work();
    79     return 0;
    80 }
  • 相关阅读:
    二叉排序树
    堆排序
    线索化二叉树
    vue 格式化代码
    线程的理解
    声明式的服务调用 Feign
    使用锁 的理解
    zookeeper 的理解
    AQS 源码解析
    HashMap 的理解与结构
  • 原文地址:https://www.cnblogs.com/weeping/p/7527626.html
Copyright © 2011-2022 走看看