CF1913F
虽然是 CF,但是赛后补题。hash, 启动!(其实是不会SA)
字符集是
但是我们不可能每次都去枚举,考虑修改一个字符对于答案的改变。
设当前修改位置为
- 本来跨过
k 的回文串都会消失
考虑怎么计算预处理这个事情。
发现当回文串形如 a b c b a 时,改变每个位置的字符后减少的回文串数量形如 1 2 3 2 1 这样先上升再下降的形式。考虑维护这个东西。
设
考虑如何维护
对于形如 a b c c b a 的字符串留给作者思考。
- 本来回文串右端点为
k-1 且回文中心小于k 的,或者本来回文串左端点为k+1 且回文中心大于k 的。
这是好维护的,用 vector 预处理每个地方有哪些回文中心,枚举
时间复杂度是
记得开 long long。
//奇回文串:形如aba,偶回文串:形如abba
#include<bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
const int N = 3e5 + 7;
const int B = 1721, M = 1e9 + 3;
int i, j, k, n, m, l, r, mid, res, sum, L, R, ans, ai;
int hl[N], hr[N], g[N];//hash使用
int p[N], q[N];//pi表示以i为回文中心的奇回文串的回文半径,q偶回文串
int c[N], dt[N];
//dt变化量,c回文串个数,
vector<int> u[N], v[N];
//u_i以i为端点的奇回文串的回文中心,v_i存偶回文串
char s[N], as;
int subl(int x, int y) {return (hl[y] - hl[x] * g[y - x] % M + M) % M;}
int subr(int x, int y) {return (hr[x] - hr[y] * g[y - x] % M + M) % M;}
void init_hash() {
for(g[0]=i=1; i<=n; i++) g[i] = g[i-1] * B % M;
for(i=1; i<=n; i++) hl[i] = (hl[i-1] * B % M + s[i]) % M;
for(i=n; i>=1; i--) hr[i] = (hr[i+1] * B % M + s[i]) % M;
}
void init_string() {
for(i=1; i<=n; i++) {
l = 0, r = min(i, n - i + 1);
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, i) == subr(i, i + mid)) res = mid, l = mid + 1;
else r = mid - 1;
}
sum += p[i] = res, l = i - res + 1, r = i + res - 1;
u[l].pb(i);
if(l != r) u[r].pb(i);
++dt[l], ++dt[r+2], dt[i+1] -= 2;
}
for(i=1; i<n; i++) {
if(s[i] != s[i+1]) continue;
l = 0, r = min(i, n - i);
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, i) == subr(i+1, i + mid + 1)) res = mid, l = mid + 1;
else r = mid - 1;
}
sum += q[i] = res, l = i - res + 1, r = i + res;
v[l].pb(i);
if(l != r) v[r].pb(i);
++dt[l], ++dt[r+2], --dt[i+1], --dt[i+2];
}
int d = 0, s = 0;
for(i=1; i<=n; i++) d += dt[i], s += d, c[i] = s;
ans = sum;
}
void solve() {
for(k=1; k<=n; k++) {
for(char s='a'; s<='z'; s++) {
int tmp = sum - c[k] + p[k];
for(int i : u[k-1]) {
if(i >= k) continue;
l = p[i] + 2, r = min(i, n - i + 1);
L = i - p[i], R = i + p[i] + 1;
if(::s[L] != s) continue;
--L; res = l - 1;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res - p[i];
}
for(int i : u[k+1]) {
if(i <= k) continue;
l = p[i] + 2, r = min(i, n - i + 1);
L = i - p[i] - 1, R = i + p[i];
if(::s[R] != s) continue;
++R; res = l - 1;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res - p[i];
}
for(int i : v[k-1]) {
if(i >= k-1) continue;//注意这里,要-1,不然会被讨论区大佬hack
L = i - q[i], R = i + q[i] + 2;
l = q[i] + 2, r = min(i, n - i);
if(::s[L] != s) continue;
--L; res = l - 1;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid + 1)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res - q[i];
}
if(::s[k-1] == s) {
i = k - 1; res = 1;
l = 2, r = min(i, n - i);
L = i - 1, R = k + 1;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid + 1)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res;
}
for(int i : v[k+1]) {
if(i <= k) continue;
L = i - q[i] - 1, R = i + q[i] + 1;
l = q[i] + 2, r = min(i, n - i);
if(::s[R] != s) continue;
++R; res = l - 1;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid + 1)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res - q[i];
}
if(::s[k+1] == s) {
i = k; res = 1;
l = 2, r = min(i, n - i);
L = k - 1, R = k + 2;
while(l <= r) {
mid = l + r >> 1;
if(subl(i - mid, L) == subr(R, i + mid + 1)) res = mid, l = mid + 1;
else r = mid - 1;
}
tmp += res;
}
if(tmp == ans) {
if(ai != k && (::s[ai] < as || (::s[ai] == as && ::s[k] > s))) ai = k, as = s;
}
if(tmp > ans) {
ans = tmp;
ai = k, as = s;
}
}
}
}
signed main() {
scanf("%lld%s", &n, s+1);
init_hash();
init_string();
solve();
s[ai] = as;
printf("%lld\n%s", ans, s+1);
return 0;
}