Link
場上思路出的最快的一題,但沒調出來。
反著考慮全為迴文串需滿足哪些情況。
若 \(k = 1\),沒有限制條件。
若 \(k = 2\),對於任意三個位置 _ _ _,先填 \(x\) \(x\) _,然後二三也要回文,第三位只能是 \(x\),最終整段區間全部相同。
若 \(k = 3\),全部相同的情況肯定滿足,考慮出現不同元素:
- _ _ _ _
- \(x\) _ \(x\) _
- \(x\) \(y\) \(x\) _
此時二到四段也要回文,最終 \(x\) \(y\) \(x\) \(y\) 交替出現。
以此類推 \(k > 3\) 的情況,得到結論:
奇數需間隔排列或全相等,偶數只能全相等。
此處有一特殊情況,若 \(k = r - l + 1\),那麼只要整段不迴文,就有 \(r - l + 1\) 的貢獻。
如何快速判斷區間全部相等?
只需維護 \(lst[i]\) 表示前一個與 \(s[i]\) 不同的元素的位置,最後判斷 \(lst[r] < l\)。
具體實現:
vector<int> lst(n, -1);
for(int i = 1; i < n; ++ i) {
if(s[i] != s[i - 1]) lst[i] = i - 1;
else lst[i] = lst[i - 1];
}
如何快速判斷元素交替出現?
維護 \(f[i][pre]\) 表示從 \(i\) 起,前一位的值是 \(pre\) 的交替段向左延伸的最大長度。
這裡再維護一個 \(L[i] = i - f[i][s[i - 1]] + 1\) 得到區間左端點,判斷 \(L[r] <= l\)。
vector<vector<int>> f(n, vector<int>(128, 1));
vector<int> L(n, 0);
for(int i = 1; i < n; ++ i) {
f[i][s[i - 1]] = 1 + f[i - 1][s[i]];
L[i] = i - f[i][s[i - 1]] + 1;
}
如何判斷區間是否迴文?
可以 \(manacher\),但我不會。
這裡用線段樹 + 字串雜湊解決,不會的可以先看這題 [ABC331F] Palindrome Query。
程式碼:
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
constexpr int N = 2e5 + 5, P = 1e9 + 7, B = 131;
int n, m, pw[N] = {1};
string s;
struct Node {
int h1, h2, sz;
} t[N * 4];
void pushup(Node &x, Node y, Node z) {
x.h1 = (1ll * y.h1 * pw[z.sz] % P + z.h1) % P;
x.h2 = (1ll * z.h2 * pw[y.sz] % P + y.h2) % P;
x.sz = y.sz + z.sz;
}
#define ls x << 1
#define rs x << 1 | 1
void build(int x, int l, int r) {
if(l == r) {
t[x] = {s[l], s[l], 1};
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(t[x], t[ls], t[rs]);
}
Node Query(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) return t[x];
Node ret = {0, 0, 0};
int mid = l + r >> 1;
if(mid >= L) pushup(ret, ret, Query(ls, l, mid, L, R));
if(mid < R) pushup(ret, ret, Query(rs, mid + 1, r, L, R));
return ret;
}
ll pre[N];
void solve() {
cin >> n >> m;
cin >> s;
build(1, 0, n - 1);
vector<int> lst(n, -1);
for(int i = 1; i < n; ++ i) {
if(s[i] != s[i - 1]) lst[i] = i - 1;
else lst[i] = lst[i - 1];
}
vector<vector<int>> f(n, vector<int>(128, 1));
vector<int> L(n, 0);
for(int i = 1; i < n; ++ i) {
f[i][s[i - 1]] = 1 + f[i - 1][s[i]];
L[i] = i - f[i][s[i - 1]] + 1;
}
for(int i = 0; i < m; ++ i) {
int l, r; cin >> l >> r;
-- l, -- r;
if(lst[r] < l) cout << 0 << '\n';
else {
ll len = r - l + 1;
ll ans = (len - 1) * len / 2;
ans --;
if(L[r] <= l) {
ans -= pre[len - 1];
}
Node tmp = Query(1, 0, n - 1, l, r);
if(tmp.h1 != tmp.h2) ans += len;
cout << ans << '\n';
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
rep(i, 3, 2e5) pre[i] = pre[i - 1] + (i & 1) * i;
rep(i, 1, 2e5) pw[i] = (1ll * pw[i - 1] * B) % P;
int T = 1;
cin >> T;
while(T --) solve();
return 0;
}