题意简述
一个字符串是“优秀”的,定义为:存在两个非空的字符串 $A,B$,满足这个字符串 $S=AABB$,那么这个 $S$ 就是优秀的。
给定一个串,计算它有多少子串是“优秀”的。相同的子串出现在不同的位置也被算两次。
长度 $\le 3e4$
思路
对于每个位置,我们维护 $pre[i]$ 表示以 $i$ 结尾的 $AA$ 形式的串有多少个,$suf[i]$ 同理。
然后答案就是 $\prod\limits_{i=1}^{n-1}pre[i]\times suf[i+1]$
然后考虑怎么求 $pre$。($suf$ 的话,就把串反过来求一遍 $pre$ 即可)
如何求 pre
不会吧?不会就对了,黑题是这么容易做出来的嘛。 我们继续降低要求,我们求特定长度的 $pre[i]$。我们设 $A$ 的长度为 $k$,也就是 $AA$ 串的长度为 $2k$ 。 这个好判断,哈希就行了。 对于位置 $i$,如果 $[i-k+1,i]$ 区间的哈希值等于区间 $[i-2k+1,i-k]$ 的哈希值,那么 $pre[i]$ 就可以 $+1$,因为长度 $k$ 满足条件。
但是这样是 $O(n^2)$ 的呀,怎么更快速的求呢。
假如现在我们枚举 $k$,能很快的求出 $[1,n]$ 的答案,那多好啊。
那有了这样一个巧妙的做法(看题解前我也不会):对于长度 $k$,我们在 $k,2k,3k…k\times (n/k)$ 的位置都打上一个标记。显然,标记的总数是 $(n/1)+(n/2)+(n/3)…+(n/n)=n\ln n$。
而且还有一个特性,一个长度为 $2k$ 的 $AA$ 串,把它分成等长度并且相同的两半,肯定各自覆盖到一个标记。
如这个图所示,蓝色是整个大串 $S$,黄色+绿色是一个串 $A$,黄色+绿色+黄色+绿色是一个 $AA$ 串。红色的是两个标记。
我们发现,黄色部分长度是两个标记的公共后缀长度之一,绿色部分则是两个标记的公共前缀长度之一。
对于每个标记,我们求出这个标记和上一个标记的最长公共前缀,和最长公共后缀(二分+哈希)。(当然,这最长公共前后缀的长度不能超过 $k$)设当前位置在 $p$,上一个标记位置是 $p-k$。 子串 $s[p,n]$ 和子串 $s[p-k,n]$ ,最长公共前缀为 $LCP$(Longest Common Prefix
),子串 $s[1,p]$ 和子串 $s[1,p-k]$ 的最长公共后缀为 $LCS$。
那么这个 $AA$ 串,长度为 $2k$,左端点最左能到 $L=p-k-LCS+1$,右端点最右能到 $R=p+LCP-1$。那么这个 $AA$ 的右端点的范围就是 $[L+2k-1,R]$。当然,这个范围不能超过 $P$ ,注意和 $P$ 取一下 $\min$ 或者 $\max$。显然,对于这个区间的所有 $pre$ 数组都能 $+1$。(因为它是一个 $AA$ 串的右端点)
我们发现,前面都是加法操作,而只要维护一次查询(最后的总查询),用差分即可。
代码
1 |
|