P8631 题解
sunkuangzheng · · 题解
- 定义
f(s) 为字符串s 的本质不同子串数量,g(s) 是字符串本质不同的长度为奇数的回文串数量,求\max\limits_{i=1}^{n-1}\{g(s[1\ldots i]) \cdot (f(s[i+1\ldots n])-g(s[i+1\ldots n]))\} 热知识:这道题在昨天还是蓝的。
我们对于
- 对于所有前后缀求
f(s) 。
这一部分是 P4070 生成魔咒,使用 SA 或 SAM 均可。
- 对于所有前后缀求
g(s) 。
注意到字符串本质不同回文子串数量是
那么这道题就做完了,时间复杂度
/**
* author: sunkuangzheng
* created: 29.02.2024 08:40:22
**/
#include<bits/stdc++.h>
#ifdef DEBUG_LOCAL
#include <mydebug/debug.h>
#endif
using ll = long long;
const int N = 5e5+5;
using namespace std;
struct SA{
int sa[N],rk[N],ok[N],h[N],st[20][N],n;
void build(string s){
n = s.size(); s = " " + s;
for(int i = 1;i <= n;i ++) sa[i] = i,rk[i] = s[i];
for(int j = 1;j < n;j *= 2){
for(int i = 1;i <= n;i ++) ok[i] = rk[i]; int p = 0;
sort(sa+1,sa+n+1,[&](int x,int y){return rk[x] < rk[y] || rk[x] == rk[y] && rk[x + j] < rk[y + j];});
auto cmp = [&](int x,int y){return ok[x] == ok[y] && ok[x + j] == ok[y + j];};
for(int i = 1;i <= n;i ++) if(cmp(sa[i],sa[i-1])) rk[sa[i]] = p; else rk[sa[i]] = ++p; if(p == n) break;
}for(int i = 1,k = 0;i <= n;h[rk[i ++]] = k)
for(k --,k = max(k,0);s[i + k] == s[sa[rk[i] - 1] + k];k ++);
for(int i = 1;i <= n;i ++) st[0][i] = h[i];
for(int j = 1;j <= __lg(n);j ++) for(int i = 1;i + (1 << j) - 1 <= n;i ++)
st[j][i] = min(st[j-1][i],st[j-1][i+(1<<j-1)]);
}int lcp(int i,int j){
if(i == j) return n - sa[i] + 1;
if(i > j) swap(i,j);
int k = __lg(j - i);
return min(st[k][i+1],st[k][j-(1<<k)+1]);
}
}s1,s2;
int T,n; string s,t; ll f[N],g[N],ans1[N],ans2[N],ans3[N];
void los(){
cin >> n >> s,t = s,s = s + '#' + string(s.rbegin(),s.rend());
s1.build(s),s2.build(t);
auto rev = [&](int i){return n + 2 + n - i;};
set<int> fk; ll sm = 0;
for(int i = n;i >= 1;i --){
auto it = fk.lower_bound(s2.rk[i]);
if(it != fk.end()) sm -= s2.h[*it],s2.h[*it] = s2.lcp(*it,s2.rk[i]),sm += s2.h[*it];
if(it != fk.begin()) s2.h[s2.rk[i]] = s2.lcp(s2.rk[i],*(--it)),sm += s2.h[s2.rk[i]];
else s2.h[s2.rk[i]] = 0;
fk.insert(s2.rk[i]),ans1[i] = 1ll * (n - i + 1) * (n - i + 2) / 2 - sm;
}fk.clear(); static set<int> f[N];
int mxr = 0;
for(int i = 1;i <= n;i ++){
int d = s1.lcp(s1.rk[i],s1.rk[rev(i)]),r = i + d - 1;
if(r > mxr){
for(int j = mxr + 1;j <= r;j ++){
int l = i - (j - i),len = j - l + 1,lcp = 0;
auto it = f[len].lower_bound(s1.rk[l]);
if(it != f[len].end()) lcp = max(lcp,s1.lcp(s1.rk[l],*it));
if(it != f[len].begin()) lcp = max(lcp,s1.lcp(s1.rk[l],*(--it)));
if(lcp < len) ans2[j] ++,f[len].insert(s1.rk[l]);
}mxr = r;
}
}int mnl = n + 1;
for(int i = 1;i <= n;i ++) f[i].clear();
for(int i = n;i >= 1;i --){
int d = s1.lcp(s1.rk[i],s1.rk[rev(i)]),l = i - d + 1;
if(l < mnl){
for(int j = mnl - 1;j >= l;j --){
int r = i + (i - j),len = r - j + 1,lcp = 0;
auto it = f[len].lower_bound(s1.rk[j]);
if(it != f[len].end()) lcp = max(lcp,s1.lcp(s1.rk[j],*it));
if(it != f[len].begin()) lcp = max(lcp,s1.lcp(s1.rk[j],*(--it)));
if(lcp < len) ans3[j] ++,f[len].insert(s1.rk[j]);
}mnl = l;
}
}ll ans = 0;
for(int i = 1;i <= n;i ++) ans2[i] += ans2[i - 1];
for(int i = n;i >= 1;i --) ans3[i] += ans3[i + 1];
for(int i = 1;i < n;i ++) ans = max(ans,1ll * ans2[i] * (ans1[i + 1] - ans3[i + 1]));
cout << ans;
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(T = 1;T --;) los();
}