zoukankan      html  css  js  c++  java
  • 【BZOJ3238】差异【后缀自动机+dp】

    题意

    分析

     这个题目还是很优秀的。sigma(len(Ti)+len(Tj))的值是一定的=n*(n+1)*(n-1)/2。那么关键就是求任意两个后缀的lcp的和了。

      我们怎么求两个后缀的lcp?如果用后缀自动机的话,我们可以先把字符串反过来,然后建后缀自动机,那么两个后缀的lcp就是他们两个在parent树上的最近公共祖先(lca)的len。我们要求的是任意两个后缀的lcp的和,我们可以考虑在parent上跑树形dp。令dp[u]为以u为lca的lcp的和。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 typedef long long LL;
     8 const int maxn=500000+100;
     9 int n;
    10 char s[maxn];
    11 struct state{
    12     int len,link;
    13     int next[26];
    14 }st[2*maxn];
    15 int last,cur,sz;
    16 int c[2*maxn],cnt[2*maxn];
    17 LL dp[2*maxn];
    18 void init(){
    19     sz=1;
    20     last=cur=0;
    21     st[0].link=-1;
    22     st[0].len=0;
    23 }
    24 void build_sam(int c){
    25     cur=sz++;
    26     cnt[cur]=1;
    27     st[cur].len=st[last].len+1;
    28     int p;
    29     for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link)
    30         st[p].next[c]=cur;
    31     if(p==-1)
    32         st[p].link=0;
    33     else{
    34         int q=st[p].next[c];
    35         if(st[q].len==st[p].len+1)
    36             st[cur].link=q;
    37         else{
    38             int clone=sz++;
    39             st[clone].len=st[p].len+1;
    40             st[clone].link=st[q].link;
    41             for(int i=0;i<26;i++)
    42                 st[clone].next[i]=st[q].next[i];
    43             for(;p!=-1&&st[p].next[c]==q;p=st[p].link)
    44                 st[p].next[c]=clone;
    45             st[cur].link=st[q].link=clone;
    46         }
    47     }
    48     last=cur;
    49 }
    50 int cmp(int a,int b){
    51     return st[a].len>st[b].len;
    52 }
    53 int main(){
    54     scanf("%s",s);
    55     n=strlen(s);
    56     init();
    57     for(int i=0;i<n;i++)
    58         build_sam(s[i]-'a');
    59     for(int i=0;i<sz;i++)
    60         c[i]=i;
    61     sort(c,c+sz,cmp );
    62     for(int i=0;i<sz;i++){
    63         int o=c[i];
    64         if(st[o].link!=-1){
    65             dp[st[o].link]+=(LL)st[st[o].link].len*cnt[o]*cnt[st[o].link];
    66             cnt[st[o].link]+=cnt[o];
    67         }
    68     }
    69 
    70     LL ans=(LL)n*(n+1)*(n-1)/2;
    71     for(int i=0;i<sz;i++){
    72         ans-=2*dp[i];
    73     }
    74     printf("%lld
    ",ans);
    75 
    76 return 0;
    77 }
    View Code
  • 相关阅读:
    Mysql 删除表
    Mysql 创建表
    Mysql left join
    Qt(Mac) 进程的启动
    Mysql update
    Mysql insert
    Mysql select
    Mysql INNER JOIN
    Mysql 别名
    Mysql 排序
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9889260.html
Copyright © 2011-2022 走看看