• SA-题目


    SA的题目

      差异https://lydsy.com/JudgeOnline/problem.php?id=3238

      题意概述:给定一个长度为 $n$ 的字符串 $S$,令 $T_ i$ 表示它从第 $i$ 个字符开始的后缀。$2<=N<=50000$。求$$sum_{1<=i<j<=n}len(T_i)+len(T_j)-2 imes lcp(T_i,T_j)$$

    ​  通过观察可以发现,每个后缀的长度被计算的次数是 $n-1$ ,而所有后缀长度的和是一个等差数列,$frac{n imes(n+1)}{2}$,所以式子的前半部分就是 $frac{(n^3-n)}{2}$ 。

    ​  现在来求后半部分,等价于所有后缀对的 $lcp$ 之和再乘二,看到后缀,我就想到 $SA$,看到 $lcp$ ,我就想到求 $height$ 数组,求出 $height$ 数组,原问题就转化为整个序列中(每个区间的最小值)之和。

    ​  这个问题可以用单调栈扫两遍,找到每个点可以作为最小值的左右端点,并注意一下边界情况,有相同最小值的时候不要算重复就可以通过了。

    ​  对于这种问题还有另一个很不错的方法:烜式合并;这是烜神仙的 $blog$ :https://www.cnblogs.com/asuldb/p/10205640.html

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cstring>
     4 # include <string>
     5 # define R register int
     6 # define ll long long
     7  8 using namespace std;
     9 10 const int maxn=500005;
    11 char c[maxn];
    12 int n,sa[maxn],ht[maxn],ta[maxn],tb[maxn],A[maxn],B[maxn],rk[maxn],m,l[maxn],r[maxn],Tp,k[maxn],v[maxn];
    13 ll ans,anss;
    14 15 inline void build_SA()
    16 {
    17     for (R i=1;i<=n;++i) ta[ c[i] ]++;
    18     for (R i=1;i<=200;++i) ta[i]+=ta[i-1];
    19     for (R i=n;i>=1;--i) sa[ ta[ c[i] ]-- ]=i;
    20     rk[ sa[1] ]=1;
    21     for (R i=2;i<=n;++i) rk[ sa[i] ]=(c[ sa[i] ]==c[ sa[i-1] ])?rk[ sa[i-1] ]:rk[ sa[i-1] ]+1;
    22     for (R l=1;rk[ sa[n] ]<n;l<<=1)
    23     {
    24         for (R i=1;i<=n;++i) ta[i]=tb[i]=0;
    25         for (R i=1;i<=n;++i)
    26         {
    27             ta[ A[i]=rk[i] ]++;
    28             tb[ B[i]=(i+l<=n)?rk[i+l]:0 ]++;
    29         }
    30         for (R i=1;i<=n;++i) ta[i]+=ta[i-1],tb[i]+=tb[i-1];
    31         for (R i=n;i>=1;--i) rk[ tb[ B[i] ]-- ]=i;
    32         for (R i=n;i>=1;--i) sa[ ta[ A[ rk[i] ] ]-- ]=rk[i];
    33         rk[ sa[1] ]=1;
    34         for (R i=2;i<=n;++i)
    35         {
    36             rk[ sa[i] ]=rk[ sa[i-1] ];
    37             if(A[ sa[i] ]!=A[ sa[i-1] ]||B[ sa[i] ]!=B[ sa[i-1] ]) rk[ sa[i] ]++;
    38         }
    39     }
    40     int j=0;
    41     for (R i=1;i<=n;++i)
    42     {
    43         if(j) j--;
    44         while (c[ i+j ]==c[ sa[ rk[i]-1 ]+j ]) j++; 
    45         ht[ rk[i] ]=j;
    46     }
    47 }
    48 49 int main()
    50 {
    51     scanf("%s",c+1);
    52     n=strlen(c+1);
    53     ans=1LL*n*(n+1)/2*(n-1);
    54     build_SA();
    55     for (R i=1;i<=n;++i)
    56     {
    57         while(Tp&&ht[i]<v[Tp]) r[ k[Tp] ]=i-k[Tp],Tp--;
    58         k[++Tp]=i,v[Tp]=ht[i];
    59     }
    60     for (R i=1;i<=Tp;++i) r[ k[i] ]=n-k[i]+1;
    61     Tp=0;
    62     for (R i=n;i>=1;--i)
    63     {
    64     while(Tp&&ht[i]<=v[Tp]) l[ k[Tp] ]=k[Tp]-i,Tp--;
    65     k[++Tp]=i,v[Tp]=ht[i];
    66     }
    67 for (R i=1;i<=Tp;++i) l[ k[i] ]=k[i]-1;
    68 for (R i=1;i<=n;++i) anss+=1LL*l[i]*r[i]*ht[i];
    69     printf("%lld",ans-anss*2);
    70     return 0;
    71 }
    差异
  • 相关阅读:
    ZOJ 1001 A + B Problem
    献给那些心软的人!!
    将表格的数据插入另一个表格
    把链接 显示为方框
    【ibus】设置ibus输入法(pinyin & sunpinyin)
    [Mongo] How to Install Mongo on Debian(不要安装)
    [Sinatra、Mongo] Mongo
    Sinatra+SQLite3+DataMapper
    [sinatra] Sinatra再入门
    [slim] Slim
  • 原文地址:https://www.cnblogs.com/shzr/p/10296957.html
Copyright © 2020-2023  润新知