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 \times lcp(T_i,T_j)$$

​  通过观察可以发现,每个后缀的长度被计算的次数是 $n-1$ ,而所有后缀长度的和是一个等差数列,$\frac{n\times(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 }
差异

 

posted @ 2019-01-23 11:39  shzr  阅读(251)  评论(0编辑  收藏  举报