CF1063F
题意
给定长度为 \(n\) 的字符串 \(s\)。
问 \(\max\{m\ |\ \exists t_1,\ t_2,\ t_3,\ ...,\ t_m,\ s\ =\ u_0\ +\ t_1\ +\ u_1\ +\ t_2\ +\ ...,\ +\ t_m\ +\ u_m,\ (u_i\) 可以为空 \(),\ \forall_{i\ <\ m}\ t_{i\ +\ 1}\) 为 \(t_i\) 子串 \(\}\) 。
\(1\ \leq\ n\ \leq\ 5\ *\ 10^5\)
做法1
令 \(f_i\) 表示 \(s_{i...n}\) 的答案,有 \(f_i\ =\ \max_{j}\ \{min(max(lcp(i,\ j),\ lcp(i\ +\ 1,\ j)),\ f_j,\ j\ -\ i\ -\ 1)\}\ +\ 1\)。
可以发现 \(f_i\ \geq\ f_{i\ +\ 1}\ -\ 1\),故直接枚举 \(f_i\) 用线段树判断是否可行。
时间复杂度:\(O(n\ log\ n)\)。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const int oo = 1e9;
struct segment_tree {
segment_tree() {}
segment_tree(int _n) {
n = _n;
N = 1;
while(N - 1 <= n) N <<= 1;
a = vector<int>(N << 1, -oo);
}
void M(int i, int x) { i |= N; a[i] = x; for (i >>= 1; i; i >>= 1) a[i] = max(a[i << 1], a[(i << 1) | 1]); return; }
int Q(int l, int r) {
int x = -oo;
for (l = (l | N) - 1, r = (r | N) + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
if(~l & 1) x = max(x, a[l ^ 1]);
if(r & 1) x = max(x, a[r ^ 1]);
}
return x;
}
private:
int n, N;
vector<int> a;
};
int main() {
ios::sync_with_stdio(false);
int n; cin >> n;
string s; cin >> s;
vector<int> sa(n + 1), rnk(n + 1), LOG(n + 1, 0);
for (int i = 2; i <= n; ++i) LOG[i] = LOG[i >> 1] + 1;
vector<vector<int> > h(LOG.back() + 1, vector<int>(n + 1, 0));
vector<int> pw2(LOG.back() + 1);
for (int i = 0; i < pw2.size(); ++i) pw2[i] = 1 << i;
auto pre_sum = [&](vector<int> &a) {
for (int i = 1; i < a.size(); ++i) a[i] += a[i - 1];
return;
};
auto build_SA = [&]() {
vector<int> freq(max(n + 5, 300), 0);
vector<pair<pair<int, int>, int> > p(n), q(n);
for (int i = 0; i < n; ++i) freq[s[i]] = 1;
pre_sum(freq);
for (int i = 0; i < n; ++i) rnk[i] = freq[s[i]];
for (int len = 1, mx = freq.back(); mx < n; len <<= 1) {
fill(freq.begin(), freq.end(), 0);
for (int i = 0; i < n; ++i) {
p[i] = make_pair(make_pair(rnk[i], (i + len < n ? rnk[i + len] : 0)), i);
++freq[p[i].first.second + 1];
}
pre_sum(freq);
for (int i = 0; i < n; ++i) q[freq[p[i].first.second]++] = p[i];
fill(freq.begin(), freq.end(), 0);
for (int i = 0; i < n; ++i) ++freq[q[i].first.first + 1];
pre_sum(freq);
for (int i = 0; i < n; ++i) p[freq[q[i].first.first]++] = q[i];
for (int i = mx = 0; i < n; ++i) {
if(!i || p[i].first != p[i - 1].first) ++mx;
rnk[p[i].second] = mx;
}
}
rnk[n] = 0;
for (int i = 0; i <= n; ++i) sa[rnk[i]] = i;
for (int i = 0, k = 0; i < n; ++i) {
if(k) --k;
int j = sa[rnk[i] - 1];
while(i + k < n && j + k < n && s[i + k] == s[j + k]) ++k;
h[0][rnk[i]] = k;
}
for (int lg = 1; lg < h.size(); ++lg) {
int len = 1 << lg - 1;
for (int i = 1; i + len <= n; ++i) h[lg][i] = min(h[lg - 1][i], h[lg - 1][i + len]);
}
return;
};
auto hQ = [&](int l, int r) {
int lg = LOG[r - l + 1];
return min(h[lg][l], h[lg][r - pw2[lg] + 1]);
};
build_SA();
int ans = 0, x = 1;
segment_tree seg1(n + 1), seg2(n + 1);
vector<vector<pair<int, int> > > eve(n);
auto lbQ = [&](int i, int x) {
int lb = 1, rb = i - 1;
while(lb <= rb) {
int mid = lb + rb >> 1;
if(hQ(mid + 1, i) < x) lb = mid + 1;
else rb = mid - 1;
}
return lb;
};
auto rbQ = [&](int i, int x) {
int lb = i + 1, rb = n;
while(lb <= rb) {
int mid = lb + rb >> 1;
if(hQ(i + 1, mid) < x) rb = mid - 1;
else lb = mid + 1;
}
return rb;
};
auto check = [&](int i, int x, int t) {
int l = lbQ(i, x), r = rbQ(i, x);
return seg1.Q(l, r) >= x || seg2.Q(l, r) - t >= x;
};
for (int i = n - 1; ~i; --i) {
for (auto t: eve[i]) {
int i = t.first, x = t.second;
seg1.M(rnk[i], x);
seg2.M(rnk[i], -oo);
}
x = max(x - 2, 0);
for(;;) {
++x;
if(!check(rnk[i], x, i) && !check(rnk[i + 1], x, i)) break;
}
ans = max(ans, x);
if(i - x - 1 >= 0) eve[i - x - 1].push_back(make_pair(i, x));
seg2.M(rnk[i], i - 1);
}
cout << ans << endl;
return 0;
}