[AHOI2013]差异

题目描述

给定一个长度为 $n$ 的字符串 $S$ ,令 $T_i$ 表示它从第 $i$ 个字符开始的后缀。求

$\displaystyle \sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j)$

其中,$\text{len}(a)$ 表示字符串 $a$ 的长度,$\text{lcp}(a,b)$ 表示字符串 $a$ 和字符串 $b$ 的最长公共前缀。

输入输出格式

输入格式:

一行,一个字符串 $S$ 。

输出格式:

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

输入输出样例

输入样例#1: 复制
cacao
输出样例#1: 复制
54

说明

对于 100% 的数据,保证 $2\leqslant n\leqslant 500000$ ,且均为小写字母。

先用后缀数组求出height数组(h数组)

那么两个点i,j的LCP就是$min{h[k] | i+1<=k<=j}$

考虑每个h[i]的贡献

假设L[i]表示L[i]~i-1的h值都大于等于h[i]

而R[i]表示i+1~R[i]的h值大于h[i](之所以不是大于等于是为了避免相同的h带来重复答案)

$ans-=2*lcp(T_i,T_j)$

$ans-=2*(i-L[i]+1)*(R[i]-i+1)*h[i]$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long lol;
 8 int n,m,c[600001];
 9 int x[600001],y[600001],SA[600001],s[600001],rank[600001],st[600001],top;
10 lol L[600001],R[600001];
11 lol h[600001],ans,sum;
12 char ch[600001];
13 void radix_sort()
14 {int i;
15   for (i=0;i<m;i++)
16     c[i]=0;
17   for (i=0;i<n;i++)
18     c[x[y[i]]]++;
19   for (i=1;i<m;i++)
20     c[i]+=c[i-1];
21   for (i=n-1;i>=0;i--)
22     SA[--c[x[y[i]]]]=y[i];
23 }
24 void build()
25 {int i,j,k,p;
26   for (i=0;i<n;i++)
27     y[i]=i,x[i]=s[i];
28   m=500000;
29   radix_sort();
30   for (k=1;k<=n;k*=2)
31     {
32       p=0;
33       for (i=n-k;i<n;i++)
34     y[p++]=i;
35       for (i=0;i<n;i++)
36     if (SA[i]>=k) y[p++]=SA[i]-k;
37       radix_sort();
38       p=1;swap(x,y);
39       x[SA[0]]=0;
40       for (i=1;i<n;i++)
41     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++;
42       if (p>n) break;
43       m=p;
44     }
45   for (i=0;i<n;i++)
46     rank[SA[i]]=i;
47   int len=0;
48   for (i=0;i<n;i++)
49     if(rank[i]>0)
50     {
51       if (len) len--;
52       j=SA[rank[i]-1];
53       while (i+len<n&&j+len<n&&(s[i+len]==s[j+len])) len++;
54       h[rank[i]]=len;
55     }
56 }
57 int main()
58 {int i,j;
59   cin>>ch;
60   n=strlen(ch);
61   for (i=0;i<n;i++)
62     {
63       s[i]=ch[i]-'a'+1;
64     }
65   build();
66   for (i=0;i<n;i++)
67     {
68       while (top&&h[i]<=h[st[top]]) top--;
69       if (top==0) L[i]=0;
70       else L[i]=st[top]+1;
71       st[++top]=i;
72     }
73   top=0;
74   for (i=n-1;i>=0;i--)
75     {
76       while (top&&h[i]<h[st[top]]) top--;
77       if (top==0) R[i]=n-1;
78       else R[i]=st[top]-1;
79       st[++top]=i;
80     }
81   for (i=1;i<=n;i++)
82     ans+=(lol)i*(lol)(n-1);
83   for (i=0;i<n;i++)
84     {
85       ans-=2ll*((lol)i-(lol)L[i]+1ll)*((lol)R[i]-(lol)i+1ll)*(lol)h[i];
86     }
87   printf("%lld\n",ans);
88 }

 

posted @ 2018-02-26 17:35  Z-Y-Y-S  阅读(313)  评论(0编辑  收藏  举报