QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#730845 | #9571. Border Jump 2 | ucup-team4435 | WA | 1ms | 3832kb | C++23 | 16.5kb | 2024-11-09 21:57:35 | 2024-11-09 21:57:35 |
Judging History
answer
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
#define all(a) begin(a), end(a)
#define len(a) int((a).size())
// source: https://judge.yosupo.jp/submission/42086
#include <algorithm>
#include <cassert>
#include <cstring>
#include <functional>
#include <initializer_list>
#include <iostream>
#include <memory>
#include <queue>
#include <random>
#include <vector>
void SA_IS(const int *s, int *SA, int n, int K) {
// s 为字符串数组[0..n-1] 必须保证 s[n-1]=0 且为最小值
// SA 为存储后缀数组[0..n-1]
// n 为字符串长度
// K 为值域
bool *t = new bool[n]; // 类型数组
int *bkt = new int[K]; // 桶
int *bkt_l = new int[K];
int *bkt_r = new int[K];
int n1 = 0; // LMS-后缀的数量
int *p1; //按出现顺序存储所有 LMS-后缀的索引
#define is_S_type(x) (t[x])
#define is_L_type(x) (!t[x])
#define is_LMS_type(x) (is_S_type(x) && x != 0 && is_L_type(x - 1))
// 预处理每一个后缀的类型
t[n - 1] = true; // 0 为 S-型后缀且为 LMS-型后缀
for (int i = n - 2; i >= 0; --i) {
t[i] = (s[i] < s[i + 1] || (is_S_type(i + 1) && s[i] == s[i + 1]));
n1 += is_LMS_type(i + 1); // s[0] 必然不是 LMS-型后缀,不会影响
}
// 预处理桶的边界
for (int i = 0; i != K; ++i) bkt[i] = 0;
for (int i = 0; i != n; ++i) ++bkt[s[i]];
for (int i = 0, sum = 0; i != K; ++i) sum += bkt[i], bkt_r[i] = sum, bkt_l[i] = sum - bkt[i];
#define indecud_sort() \
do { \
for (int i = 0; i != K; ++i) bkt[i] = bkt_l[i]; \
for (int i = 0, j; i != n; ++i) \
if ((j = SA[i] - 1) >= 0 && is_L_type(j)) SA[bkt[s[j]]++] = j; \
for (int i = 0; i != K; ++i) bkt[i] = bkt_r[i]; \
for (int i = n - 1, j; i >= 0; --i) \
if ((j = SA[i] - 1) >= 0 && is_S_type(j)) SA[--bkt[s[j]]] = j; \
} while (0)
// 将所有 LMS-后缀放入 SA 对应桶的末尾并诱导排序
p1 = new int[n1];
for (int i = 0, j = 0; i != n; ++i) {
SA[i] = -1;
if (is_LMS_type(i)) p1[j++] = i;
}
for (int i = 0; i != K; ++i) bkt[i] = bkt_r[i];
for (int i = n1 - 1; i >= 0; --i) SA[--bkt[s[p1[i]]]] = p1[i];
indecud_sort();
int *s1 = new int[n1]; // 新的字符串
int *SA1 = new int[n1]; // 存储新的字符串排的后缀数组
for (int i = 0, j = 0; i != n; ++i)
if (is_LMS_type(SA[i])) SA1[j++] = SA[i]; // 存储 LMS-子串的相对顺序
int name = 0;
// 对所有 LMS-子串命名
for (int i = 0, prev = -1; i != n1; ++i) {
int pos = SA1[i];
for (int j = 0;; ++j) // 无需设置范围,因为 s[n-1]=0 为最小值且不会出现在其余位置
if (prev == -1 || s[pos + j] != s[prev + j] || is_S_type(pos + j) != is_S_type(prev + j)) {
prev = pos, ++name;
break;
} else if (j != 0 && (is_LMS_type(pos + j) || is_LMS_type(prev + j))) // 到末尾了停止比较
break;
SA[pos] = name - 1; // 利用 SA 暂时存储新字符串的 name
}
for (int i = 0; i != n1; ++i) s1[i] = SA[p1[i]];
if (name != n1)
SA_IS(s1, SA1, n1, name);
else
for (int i = 0; i != n1; ++i) SA1[s1[i]] = i;
for (int i = 0; i != K; ++i) bkt[i] = bkt_r[i];
for (int i = 0; i != n; ++i) SA[i] = -1;
for (int i = n1 - 1; i >= 0; --i) SA[--bkt[s[p1[SA1[i]]]]] = p1[SA1[i]];
indecud_sort();
delete[] SA1;
delete[] s1;
delete[] p1;
delete[] bkt_r;
delete[] bkt_l;
delete[] bkt;
delete[] t;
#undef is_S_type
#undef is_L_type
#undef is_LMS_type
#undef indecud_sort
}
std::vector<int> get_sa(const std::string &s) {
int len = s.size();
std::vector<int> SA(len + 1), s_cpy(len + 1);
for (int i = 0; i != len; ++i) s_cpy[i] = s[i];
s_cpy.back() = 0;
SA_IS(s_cpy.data(), SA.data(), len + 1, 128);
return std::vector<int>(SA.begin() + 1, SA.end());
}
struct suffix_array {
std::vector<int> order, suffix_position, lcp;
template<typename T>
suffix_array(T str = T()) {
int n = str.size() + 1;
order = get_sa(str);
order.insert(order.begin(), n - 1);
suffix_position.resize(n);
for (int i = 0; i < n; i++) {
suffix_position[order[i]] = i;
}
lcp.resize(n);
int current_lcp = 0;
for (int suffix = 0; suffix < n - 1; suffix++, current_lcp = current_lcp == 0 ? 0 : current_lcp - 1) {
int previous_suffix = order[suffix_position[suffix] - 1];
while (str[suffix + current_lcp] == str[previous_suffix + current_lcp])
current_lcp++;
lcp[suffix_position[suffix]] = current_lcp;
}
}
};
/*
* Zero based.
* Type T must have operator += T.
* Type T must have default constructor, which sets neutral value.
* Operation += must be commutative.
* For segment query type T must have operator -= T.
*/
template<typename T>
struct binary_indexed_tree {
std::vector<T> bit;
// Fills the array with default values.
binary_indexed_tree(int n = 0) : bit(n + 1) {}
int size() const {
return int(bit.size()) - 1;
}
// Adds delta at the position pos.
void add(int pos, T delta) {
for (pos++; pos < static_cast<int>(bit.size()); pos += pos & -pos) {
bit[pos] += delta;
}
}
// Returns the sum on the segment [0, pref].
T query(int pref) {
T sum = T();
for (pref++; pref > 0; pref -= pref & -pref) {
sum += bit[pref];
}
return sum;
}
// Returns the sum on the interval [l, r).
T query(int l, int r) {
if (r <= l) {
return T();
}
T res = query(r - 1);
res -= query(l - 1);
return res;
}
};
/*
* Zero based.
* Works for operations Op, such that Op(S) = Op(S \cup x), where x in S (like min, max, gcd...).
* Operation must be commutative.
*/
template<typename T, typename merge_t = std::function<T(T, T)>>
class sparse_table {
private:
std::vector<std::vector<T>> sparse;
const merge_t merge;
public:
sparse_table(const merge_t &merge) : merge(merge) {}
sparse_table(const std::vector<T> &a, const merge_t &merge) : merge(merge) {
const int n = a.size(), lg = std::__lg(std::max(1, n));
sparse.reserve(lg + 1);
sparse.push_back(a);
for (int level = 1; level <= lg; level++) {
sparse.push_back(std::vector<T>(n - (1 << level) + 1));
for (int i = 0; i < static_cast<int>(sparse[level].size()); i++) {
sparse[level][i] = merge(sparse[level - 1][i], sparse[level - 1][i + (1 << (level - 1))]);
}
}
}
sparse_table(const sparse_table &sparse) : sparse(sparse.sparse), merge(sparse.merge) {}
sparse_table& operator=(const sparse_table<T, merge_t> &another) {
sparse = another.sparse;
return *this;
}
// Returns result of merging elements on the interval [l, r).
T query(int l, int r) const {
assert(l < r);
const int level = std::__lg(r - l);
return merge(sparse[level][l], sparse[level][r - (1 << level)]);
}
};
/*
* Node must have default constructor.
* Node must have static function merge.
* Node must have .push and .clear_after_push methods.
*/
template<typename node>
class segtree {
private:
void build(int v, int vl, int vr) {
if (vr - vl <= 1)
return;
int vm = (vl + vr) >> 1;
build(v << 1, vl, vm);
build(v << 1 | 1, vm, vr);
tree[v] = node::merge(tree[v << 1], tree[v << 1 | 1]);
}
template<typename T>
void build(int v, int vl, int vr, const std::vector<T> &arr) {
if (vl == vr)
return;
if (vr - vl == 1) {
tree[v] = node(arr[vl]);
return;
}
int vm = (vl + vr) >> 1;
build(v << 1, vl, vm, arr);
build(v << 1 | 1, vm, vr, arr);
tree[v] = node::merge(tree[v << 1], tree[v << 1 | 1]);
}
template<typename... Args>
void _update(int v, int vl, int vr, int l, int r, Args&&... args) {
if (r <= vl || vr <= l)
return;
if (l <= vl && vr <= r) {
tree[v].apply(std::forward<Args>(args)..., vl, vr);
return;
}
int vm = (vl + vr) >> 1;
tree[v].push(tree[v << 1], vl, vm);
tree[v].push(tree[v << 1 | 1], vm, vr);
tree[v].clear_after_push();
_update(v << 1, vl, vm, l, r, std::forward<Args>(args)...);
_update(v << 1 | 1, vm, vr, l, r, std::forward<Args>(args)...);
tree[v] = node::merge(tree[v << 1], tree[v << 1 | 1]);
}
node _query(int v, int vl, int vr, int l, int r) {
if (l <= vl && vr <= r)
return tree[v];
int vm = (vl + vr) >> 1;
tree[v].push(tree[v << 1], vl, vm);
tree[v].push(tree[v << 1 | 1], vm, vr);
tree[v].clear_after_push();
if (r <= vm)
return _query(v << 1, vl, vm, l, r);
if (vm <= l)
return _query(v << 1 | 1, vm, vr, l, r);
return node::merge(_query(v << 1, vl, vm, l, r), _query(v << 1 | 1, vm, vr, l, r));
}
template<typename T>
int _find_first(int v, int vl, int vr, int from, const T &checker) {
if (vr <= from)
return n;
if (from <= vl && !checker(tree[v], vl, vr))
return n;
if (vr - vl == 1)
return vl;
int vm = (vl + vr) >> 1;
tree[v].push(tree[v << 1], vl, vm);
tree[v].push(tree[v << 1 | 1], vm, vr);
tree[v].clear_after_push();
int res = _find_first(v << 1, vl, vm, from, checker);
return res == n ? _find_first(v << 1 | 1, vm, vr, from, checker) : res;
}
template<typename T>
int _find_last(int v, int vl, int vr, int from, const T &checker) {
if (from <= vl)
return -1;
if (vr <= from && !checker(tree[v], vl, vr))
return -1;
if (vr - vl == 1)
return vl;
int vm = (vl + vr) >> 1;
tree[v].push(tree[v << 1], vl, vm);
tree[v].push(tree[v << 1 | 1], vm, vr);
tree[v].clear_after_push();
int res = _find_last(v << 1 | 1, vm, vr, from, checker);
return res == -1 ? _find_last(v << 1, vl, vm, from, checker) : res;
}
public:
int n;
std::vector<node> tree;
segtree(int n) : n(n), tree(4 * n, node()) {
build(1, 0, n);
}
template<typename T>
segtree(const std::vector<T> &arr) : n(arr.size()), tree(4 * n) {
build(1, 0, n, arr);
}
int size() const {
return n;
}
template<typename... Args>
void update(int l, int r, Args&&... args) {
if (r <= l)
return;
_update(1, 0, n, l, r, std::forward<Args>(args)...);
}
node query(int l, int r) {
assert(std::max(0, l) < std::min(n, r)); // or return node() in this case
return _query(1, 0, n, l, r);
}
// Trying to find first true on the interval [from, n).
// Returns n if not found.
template<typename T>
int find_first(int from, const T &checker) {
return _find_first(1, 0, n, from, checker);
}
// Trying to find last true on the interval [0, from).
// Returns -1 if not found.
template<typename T>
int find_last(int from, const T &checker) {
return _find_last(1, 0, n, from, checker);
}
};
struct node {
int mx = -1e9;
node() {}
void apply(ll delta, int, int) {
mx = delta;
}
void push(node&, int, int) {}
void clear_after_push() {}
static node merge(const node &left, const node &right) {
node res;
res.mx = max(left.mx, right.mx);
return res;
}
};
void solve(int /* test_num */) {
string s;
cin >> s;
int n = len(s);
auto t = s + "#";
auto reversed = s;
reverse(all(reversed));
t += reversed;
suffix_array sa(t);
auto merge_min = [](int x, int y) {
return x < y ? x : y;
};
sparse_table<int, decltype(merge_min)> sparse(sa.lcp, merge_min);
vector<int> dp(n, n - 1);
int ans = 0;
const int ITS = __lg(n) + 2;
for (int it = 1; it <= ITS; it++) {
segtree<node> tree(2 * n + 2);
int max_r = -1;
for (int l = 0; l < n; l++) {
while (max_r < dp[l]) {
max_r++;
int pos = sa.suffix_position[n + 1 + (n - 1 - max_r)];
tree.update(pos, pos + 1, max_r);
}
int lb = 0, rb = max_r - l + 1;
while (rb - lb > 1) {
int mid = (lb + rb) / 2;
int pos = sa.suffix_position[l];
int left;
{
int low = -1, high = pos;
while (high - low > 1) {
int mid2 = (low + high) / 2;
if (sparse.query(mid2 + 1, pos + 1) < mid) {
low = mid2;
} else {
high = mid2;
}
}
left = high;
}
int right;
{
int low = pos, high = 2 * n + 2;
while (high - low > 1) {
int mid2 = (low + high) / 2;
if (sparse.query(pos + 1, mid2 + 1) >= mid) {
low = mid2;
} else {
high = mid2;
}
}
right = low;
}
if (tree.query(left, right + 1).mx - mid + 1 > l) {
lb = mid;
} else {
rb = mid;
}
}
if (lb == 0) {
dp[l] = -1;
continue;
}
ans = max(ans, it);
dp[l] = l + lb - 1;
}
}
vector<int> nxt(n + 1, n);
for (int i = n - 2; i >= 0; i--) {
if (s[i] != s[i + 1]) {
nxt[i] = i + 1;
} else {
nxt[i] = nxt[i + 1];
}
}
vector<int> prev(n, -1);
for (int i = 1; i < n; i++) {
if (s[i] != s[i - 1]) {
prev[i] = i - 1;
} else {
prev[i] = prev[i - 1];
}
}
auto check = [&] (int l, int r) {
if (l >= r) return;
bool ok = true;
for (int d = 0; d <= r - l && ok; d++) {
ok &= s[l + d] == s[r - d];
}
if (!ok) return;
int length = r - l + 1;
if (length % 2 == 1) {
int mid = (l + r) / 2;
int rr = nxt[mid] - 1;
int ll = prev[mid] + 1;
ll = max(ll, mid - (rr - mid));
rr = min(rr, mid + (mid - ll));
ans = max(ans, ITS + length / 2 + (rr - ll) / 2);
} else {
int mid = (l + r) / 2;
if (s[mid] != s[mid + 1]) {
ans = max(ans, ITS + length / 2);
} else {
int ll = prev[mid] + 1;
int rr = nxt[mid] - 1;
ll = max(ll, mid - (rr - mid - 1));
rr = min(rr, mid + 1 + (mid - ll));
ans = max(ans, ITS + length / 2 + (rr - ll + 1) / 2);
}
}
};
for (int l = 0; l < n; l++) {
if (dp[l] == -1) {
continue;
}
int r = dp[l];
check(l, r);
check(l + 1, r);
check(l, r - 1);
}
cout << ans << '\n';
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int tests;
cin >> tests;
for (int test_num = 1; test_num <= tests; test_num++) {
solve(test_num);
}
}
详细
Test #1:
score: 100
Accepted
time: 0ms
memory: 3592kb
input:
3 aaaa abbaabba xy
output:
3 4 0
result:
ok 3 number(s): "3 4 0"
Test #2:
score: 0
Accepted
time: 0ms
memory: 3684kb
input:
15 eeee ooom bbcb yyaa ssdn wgww hrhr exer hcch qyyy lppa ocvo orxr lrjj pztv
output:
3 2 1 1 1 1 1 1 2 2 1 1 1 1 0
result:
ok 15 numbers
Test #3:
score: 0
Accepted
time: 1ms
memory: 3604kb
input:
52 eeeee oooom bbbcb yyyaa sssdn wwgww hhrhr eexer hhcch qqyyy llppa oocvo oorxr llrjj ppztv tnttt vnvvn hthhp jzjzj nrnrr gqgqt uruyu cdchd djdhh ktkfy piipp zaaza uffuq bvvvb hkkkk pcccj qccpq wqqaq appgg cxxvg ewfee peupe odfof kdpkh zotoz yzkzz irtrt vxyxi dlood akrrk nsbbb rdjjc bfexb uxsex ise...
output:
4 3 2 2 2 2 1 1 2 2 1 1 1 1 1 2 2 1 2 1 1 1 1 1 1 2 2 2 3 3 2 1 1 1 1 1 1 1 1 2 1 1 1 1 2 2 1 1 1 1 1 0
result:
ok 52 numbers
Test #4:
score: -100
Wrong Answer
time: 1ms
memory: 3832kb
input:
203 eeeeee ooooom bbbbcb yyyyaa ssssdn wwwgww hhhrhr eeexer hhhcch qqqyyy lllppa ooocvo ooorxr lllrjj pppztv ttnttt vvnvvn hhthhp jjzjzj nnrnrr ggqgqt uuruyu ccdchd ddjdhh kktkfy ppiipp zzaaza uuffuq bbvvvb hhkkkk ppcccj qqccpq wwqqaq aappgg ccxxvg eewfee ppeupe oodfof kkdpkh zzotoz yyzkzz iirtrt vv...
output:
6 4 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 3 2 2 3 3 2 1 1 1 1 2 1 1 1 2 1 1 1 1 2 2 1 1 1 1 1 1 3 3 2 3 2 2 1 1 1 1 2 2 2 2 2 1 1 1 1 1 1 2 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 4 4 3 2 2 2 2 1 1 1 1 1 2 1 1 1 2 2 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 2 2 2 1 2 2 ...
result:
wrong answer 1st numbers differ - expected: '5', found: '6'