改进了一下 @\(\bf{ \color{black}\text{唐}\color{red} \text{一文}}\) 大佬的做法。
tags:
-
\(\text{strings}\)
-
\(\color{red}*2900\)
给出一个字符串 \(s\),求 \(s\) 有多少对相交的回文子串(不考虑顺序)。
\(|s|\le 2\times 10^6\)。
\(2.00\,\text{s}\,/\,125.00\,\text{MB}\)。
考虑容斥,用回文子串对数减去不相交的。记 \(tot\) 表示回文子串个数,\(L_i\) 表示以 \(i\) 开头的回文子串个数,\(R_i\) 表示以 \(i\) 结尾的回文子串个数,则答案为:
\[\dfrac{tot\cdot (tot-1)}{2}-\sum\limits_{i=1}^{|s|} \left(R_i\cdot \sum\limits_{j=i+1}^{|s|} L_j\right) \]简单解释一下,就是枚举左边回文子串的结尾位置,那么所有开头位置大于这个位置的回文子串与其不相交。
考虑如何求出 \(tot\),枚举中心 \(i\),分奇数、偶数长度讨论,可以发现若一个子串是回文串,那把它两端的字符去掉其仍然是回文串,即答案有单调性。
维护正反串哈希值,考虑二分 + 哈希求出出最长的奇数 / 偶数分别是第几个。记为 \(f0,f1\),那么它带来了 \(f0+f1\) 个回文子串。
而且可以发现,以奇数为例,对于 \([i-f0+1,i]\) 这些位置又可以作为当前回文串的左端点,相当于 \(L\) 区间 \(+1\);\([i,i+f0-1]\) 这些位置可以作为右端点,相当于 \(R\) 区间 \(+1\)。
由于只有一次查询,而且还是在最后,考虑维护差分数组并前缀和,就可以求出 \(L_i,R_i\)。
最后枚举 \(i\),维护一下 \(L\) 的后缀和直接算即可。
时间复杂度为 \(\mathcal{O}(|s|\log |s|)\),空间复杂度为 \(\mathcal{O}(|s|)\)。
提交记录(\(\color{limegreen}\bf Accepted\) \(\boldsymbol{590\,\text{ms}\,/\,52008\,\text{KB}}\),含代码)
标签:子串,f0,color,CF17E,tot,Palisection,text,回文 From: https://www.cnblogs.com/MnZnOIerLzy/p/17828736.html