P9482 [NOI2023] 字符串
P9482 [NOI2023] 字符串
设
先考虑朴素的
我们发现,没有很好的后缀数据结构精确刻画所有
相比于 “子串”,我们肯定更希望看到 “前缀” 或 “后缀”,因为前者有
首先思考这样做对答案造成的影响:如果满足条件
尝试推出条件
综上,我们将问题分成两部分:计算
第一部分相当容易:对
第二部分相对困难一些。称 长度为偶数 的回文串
尝试刻画所有回文串,有两种方式:Manacher 和 PAM。因为我不会 PAM,所以考虑 Manacher,它求出了以所有位置或间隔为回文中心的最长回文半径。由于要求长度为偶数,所以本题只用到了以间隔为回文中心的最长回文半径。
接下来是本题最核心的观察:回文串具有一定对称性。考虑
现在问题转化为:给平面上一条斜率为
总时间复杂度
同学用了一些牛鬼蛇神方法,复杂度形如
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdi = pair<double, int>;
using pdd = pair<double, double>;
using ull = unsigned long long;
#define ppc(x) __builtin_popcount(x)
#define clz(x) __builtin_clz(x)
bool Mbe;
// mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937_64 rnd(1064);
int rd(int l, int r) {
return rnd() % (r - l + 1) + l;
}
constexpr int mod = 1e9 + 7;
void addt(int &x, int y) {
x += y, x >= mod && (x -= mod);
}
int add(int x, int y) {
return x += y, x >= mod && (x -= mod), x;
}
int ksm(int a, int b) {
int s = 1;
while(b) {
if(b & 1) s = 1ll * s * a % mod;
a = 1ll * a * a % mod, b >>= 1;
}
return s;
}
constexpr int Z = 1e6 + 5;
int fc[Z], ifc[Z];
int bin(int n, int m) {
if(n < m) return 0;
return 1ll * fc[n] * ifc[m] % mod * ifc[n - m] % mod;
}
void init_fac(int Z) {
for(int i = fc[0] = 1; i < Z; i++) fc[i] = 1ll * fc[i - 1] * i % mod;
ifc[Z - 1] = ksm(fc[Z - 1], mod - 2);
for(int i = Z - 2; ~i; i--) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % mod;
}
// ---------- templates above ----------
constexpr int N = 2e5 + 5;
int n, m, q;
char s[N], t[N];
ll ans[N];
namespace SA {
int sa[N], rk[N];
int buc[N], ork[N], id[N];
bool cmp(int a, int b, int w) {
return ork[a] == ork[b] && ork[a + w] == ork[b + w];
}
void build(int n) {
memset(buc, 0, N << 2);
int m = 1 << 7, p = 0;
for(int i = 1; i <= n; i++) buc[rk[i] = t[i]]++;
for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
for(int i = n; i; i--) sa[buc[rk[i]]--] = i;
for(int w = 1; ; w <<= 1, m = p, p = 0) {
for(int i = n - w + 1; i <= n; i++) id[++p] = i;
for(int i = 1; i <= n; i++) if(sa[i] > w) id[++p] = sa[i] - w;
memset(buc, 0, N << 2);
memcpy(ork, rk, N << 2), p = 0;
for(int i = 1; i <= n; i++) buc[rk[i]]++;
for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
for(int i = n; i; i--) sa[buc[rk[id[i]]]--] = id[i];
for(int i = 1; i <= n; i++) rk[sa[i]] = cmp(sa[i - 1], sa[i], w) ? p : ++p;
if(p == n) break;
}
}
}
struct BIT {
int c[N];
void clear() {
memset(c, 0, N << 2);
}
void add(int x, int v) {
while(x < N) c[x] += v, x += x & -x;
}
int query(int x) {
int s = 0;
while(x) s += c[x], x -= x & -x;
return s;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
};
namespace Part1 {
struct dat {
int id, l, r;
};
vector<dat> qu[N];
void add(int i, int r, int id) {
qu[SA::rk[i]].push_back({id, i + 1, i + r + r - 1});
}
BIT odd, eve;
void solve() {
odd.clear(), eve.clear();
for(int i = m; i; i--) {
int pos = SA::sa[i];
if(pos <= n) {
for(dat it : qu[i]) {
if(it.l & 1) ans[it.id] += odd.query(it.l, it.r);
else ans[it.id] += eve.query(it.l, it.r);
}
}
else if(pos > n + 1 && pos < m) {
pos = m - pos;
if(pos & 1) odd.add(pos, 1);
else eve.add(pos, 1);
}
}
for(int i = 1; i < N; i++) qu[i].clear();
}
}
namespace Part2 {
vector<pii> qu[N], ad[N];
void add(int i, int r, int id) {
qu[i].push_back({i + r, id});
}
BIT tr;
int R[N];
char u[N];
void solve() {
tr.clear();
int cnt = 0;
u[0] = ',', u[cnt = 1] = '?';
for(int i = 1; i <= n; i++) {
u[++cnt] = s[i];
u[++cnt] = '?';
}
u[++cnt] = '!';
for(int i = 1, c = 0, r = 0; i < cnt; i++) {
R[i] = i > r ? 1 : min(r - i + 1, R[c + c - i]);
while(u[i - R[i]] == u[i + R[i]]) R[i]++;
if(i + R[i] - 1 > r) c = i, r = i + R[i] - 1;
}
for(int i = 2; i <= n; i++) {
int r = R[i * 2 - 1] >> 1;
if(!r || s[i + r] >= s[i - r - 1]) continue;
ad[i - r].push_back({i, 1});
ad[i].push_back({i, -1});
}
for(int i = 1; i <= n; i++) {
for(pii it : ad[i]) tr.add(it.first, it.second);
for(pii it : qu[i]) ans[it.second] -= tr.query(it.first);
}
for(int i = 1; i < N; i++) {
qu[i].clear();
ad[i].clear();
}
}
}
void mian() {
cin >> n >> q >> s + 1, m = 0;
for(int i = 1; i <= n; i++) t[++m] = s[i];
t[++m] = 57;
for(int i = n; i; i--) t[++m] = s[i];
t[++m] = 40;
SA::build(m);
for(int _ = 1; _ <= q; _++) {
int i, r;
cin >> i >> r;
Part1::add(i, r, _);
Part2::add(i, r, _);
}
Part1::solve();
Part2::solve();
for(int i = 1; i <= q; i++) {
cout << ans[i] << "\n";
ans[i] = 0;
}
}
bool Med;
int main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int c, T = 1;
cin >> c >> T;
while(T--) mian();
cerr << 1e3 * clock() / CLOCKS_PER_SEC << " ms\n";
return 0;
}