QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#368544 | #4631. Interesting String Problem | hos_lyric | RE | 123ms | 11624kb | C++14 | 12.7kb | 2024-03-27 12:02:25 | 2024-03-27 12:02:26 |
Judging History
answer
#include <cassert>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
using Int = long long;
template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; };
template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; }
template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; }
template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; }
template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; }
#define COLOR(s) ("\x1b[" s "m")
////////////////////////////////////////////////////////////////////////////////
// SA-IS
// String: string, vector<int>, vector<long long>
// if sigma <= n, O(n) time, O(n) space
// if sigma > n, O(n log n) time, O(n) space
template <class String> vector<int> suffixArrayRec(const String &as) {
const int n = as.size();
if (n == 0) return {};
const auto minmaxA = minmax_element(as.begin(), as.end());
const auto minA = *minmaxA.first, maxA = *minmaxA.second;
if (static_cast<unsigned long long>(maxA) - minA >=
static_cast<unsigned long long>(n)) {
vector<int> us(n);
for (int u = 0; u < n; ++u) us[u] = u;
std::sort(us.begin(), us.end(), [&](int u, int v) -> bool {
return (as[u] < as[v]);
});
int b = 0;
vector<int> bs(n, 0);
for (int i = 1; i < n; ++i) {
if (as[us[i - 1]] != as[us[i]]) ++b;
bs[us[i]] = b;
}
return suffixArrayRec(bs);
}
const int sigma = maxA - minA + 1;
vector<int> pt(sigma + 1, 0), poss(sigma);
for (int u = 0; u < n; ++u) ++pt[as[u] - minA + 1];
for (int a = 0; a < sigma; ++a) pt[a + 1] += pt[a];
// cmp[u] := (as[u, n) < as[u + 1, n))
vector<bool> cmp(n);
cmp[n - 1] = false;
for (int u = n - 1; --u >= 0; ) {
cmp[u] = (as[u] != as[u + 1]) ? (as[u] < as[u + 1]) : cmp[u + 1];
}
// ><, nn - id (0 <= id < n)
int nn = 0;
vector<int> ids(n, 0);
int last = n;
vector<int> nxt(n, 0);
// put ><, from the tail of each bucket
vector<int> us(n, 0);
memcpy(poss.data(), pt.data() + 1, sigma * sizeof(int));
for (int u = n - 1; --u >= 1; ) if (!cmp[u - 1] && cmp[u]) {
ids[u] = ++nn;
nxt[u] = last;
last = u;
us[--poss[as[u] - minA]] = u;
}
// follow > backwards, from the head of each bucket
memcpy(poss.data(), pt.data(), sigma * sizeof(int));
us[poss[as[n - 1] - minA]++] = n - 1;
for (int i = 0; i < n; ++i) {
const int u = us[i];
if (u && !cmp[u - 1]) us[poss[as[u - 1] - minA]++] = u - 1;
}
// follow < backwards, from the tail of each bucket
memcpy(poss.data(), pt.data() + 1, sigma * sizeof(int));
for (int i = n; --i >= 0; ) {
const int u = us[i];
if (u && cmp[u - 1]) us[--poss[as[u - 1] - minA]] = u - 1;
}
if (nn) {
int vsLen = 0;
vector<int> vs(nn);
for (const int u : us) if (ids[u]) vs[vsLen++] = u;
int b = 0;
vector<int> bs(nn, 0);
for (int j = 1; j < nn; ++j) {
// as[v1, w1] (< or =) as[v0, w0]
int v1 = vs[j - 1], v0 = vs[j];
const int w1 = nxt[v1], w0 = nxt[v0];
if (w1 - v1 != w0 - v0) {
++b;
} else {
for (; ; ++v1, ++v0) {
if (v1 == n) { ++b; break; }
if (as[v1] != as[v0]) { ++b; break; }
if (v1 == w1) break;
}
}
bs[nn - ids[vs[j]]] = b;
}
for (int u = 0; u < n; ++u) if (ids[u]) vs[nn - ids[u]] = u;
const auto sub = suffixArrayRec(bs);
// put ><, from the tail of each bucket
memset(us.data(), 0, n * sizeof(int));
memcpy(poss.data(), pt.data() + 1, sigma * sizeof(int));
for (int j = nn; --j >= 0; ) {
const int u = vs[sub[j]];
us[--poss[as[u] - minA]] = u;
}
// follow > backwards, from the head of each bucket
memcpy(poss.data(), pt.data(), sigma * sizeof(int));
us[poss[as[n - 1] - minA]++] = n - 1;
for (int i = 0; i < n; ++i) {
const int u = us[i];
if (u && !cmp[u - 1]) us[poss[as[u - 1] - minA]++] = u - 1;
}
// follow < backwards, from the tail of each bucket
memcpy(poss.data(), pt.data() + 1, sigma * sizeof(int));
for (int i = n; --i >= 0; ) {
const int u = us[i];
if (u && cmp[u - 1]) us[--poss[as[u - 1] - minA]] = u - 1;
}
}
return us;
}
// us[i]: i-th suffix
// su[u]: index of as[u, n)
// hs[i]: longest common prefix of as[us[i - 1], n) and as[us[i], n)
struct SuffixArray {
int n;
bool rmq;
vector<int> us, su, hs;
SuffixArray() : n(0), rmq(false) {}
SuffixArray(const string &as, bool rmq_) : rmq(rmq_) { build(as); }
SuffixArray(const vector<int> &as, bool rmq_) : rmq(rmq_) { build(as); }
SuffixArray(const vector<long long> &as, bool rmq_) : rmq(rmq_) { build(as); }
template <class String> void build(const String &as) {
n = as.size();
us = suffixArrayRec(as);
su.resize(n + 1);
for (int i = 0; i < n; ++i) su[us[i]] = i;
su[n] = -1;
hs.assign(n, 0);
for (int h = 0, u = 0; u < n; ++u) if (su[u]) {
for (int v = us[su[u] - 1]; v + h < n && as[v + h] == as[u + h]; ++h) {}
hs[su[u]] = h;
if (h) --h;
}
if (rmq) {
const int logN = n ? (31 - __builtin_clz(n)) : 0;
hs.resize((logN + 1) * n - (1 << logN) + 1);
for (int e = 0; e < logN; ++e) {
int *hes = hs.data() + e * n;
for (int i = 0; i <= n - (1 << (e + 1)); ++i) {
hes[n + i] = min(hes[i], hes[i + (1 << e)]);
}
}
}
}
// Returns longest common prefix of as[u, n) and as[v, n).
// 0 <= u, v <= n
// Assumes rmq.
inline int lcp(int u, int v) const {
if (u == v) return n - u;
int i = su[u], j = su[v];
if (i > j) swap(i, j);
const int e = 31 - __builtin_clz(j - i);
return min(hs[e * n + i + 1], hs[e * n + j + 1 - (1 << e)]);
}
};
////////////////////////////////////////////////////////////////////////////////
// 0 <= u <= n: suffix [u, n) (n: root, empty string)
// n < u < m: LCA needed
struct SuffixTree {
int n, m;
SuffixArray sa;
struct Node {
int par, len, occ;
inline int l() const { return occ; }
inline int r() const { return occ + len; }
};
vector<Node> nodes;
// considering character order
vector<vector<int>> graph;
int zeit = 0;
vector<int> dis, fin, sid;
SuffixTree() {}
SuffixTree(const string &str, bool lastOcc) { build(str, lastOcc); }
SuffixTree(const vector<int> &str, bool lastOcc) { build(str, lastOcc); }
SuffixTree(const vector<long long> &str, bool lastOcc) { build(str, lastOcc); }
template <class String> void build(const String &str, bool lastOcc) {
n = str.size();
m = n + 1;
sa = SuffixArray(str, /*rmq=*/false);
nodes.resize(2 * n + 1);
graph.resize(2 * n + 1);
nodes[n] = Node{/*par=*/-1, /*len=*/0, /*occ=*/lastOcc ? n : 0};
int top = 0;
vector<int> stack(n + 1);
stack[0] = n;
for (int i = 0; i < n; ++i) {
const int u = sa.us[i];
int v = -1;
for (; nodes[stack[top]].len > sa.hs[i]; --top) {
v = stack[top];
nodes[nodes[v].par].occ = lastOcc ? max(nodes[nodes[v].par].occ, nodes[v].occ) : min(nodes[nodes[v].par].occ, nodes[v].occ);
}
if (nodes[stack[top]].len < sa.hs[i]) {
const int w = m++;
nodes[w] = Node{/*par=*/nodes[v].par, /*len=*/sa.hs[i], /*occ=*/nodes[v].occ};
graph[nodes[v].par].back() = w;
graph[w].push_back(v);
stack[++top] = nodes[v].par = w;
}
nodes[u] = Node{/*par=*/stack[top], /*len=*/n - u, /*occ=*/u};
graph[nodes[u].par].push_back(u);
stack[++top] = u;
}
for (; top; --top) {
const int v = stack[top];
nodes[nodes[v].par].occ = lastOcc ? max(nodes[nodes[v].par].occ, nodes[v].occ) : min(nodes[nodes[v].par].occ, nodes[v].occ);
}
nodes.resize(m);
graph.resize(m);
dis.assign(m, -1);
fin.assign(m, -1);
dfs(n);
assert(zeit == m);
sid.assign(m, -1);
for (int u = 0; u < m; ++u) sid[dis[u]] = u;
}
inline const Node &operator[](int u) const {
return nodes[u];
}
inline int size(int u) const {
return (~nodes[u].par) ? (nodes[u].len - nodes[nodes[u].par].len) : 1;
}
inline int parJ(int j) const {
return dis[nodes[sid[j]].par];
}
void dfs(int u) {
dis[u] = zeit++;
for (const int v : graph[u]) dfs(v);
fin[u] = zeit;
}
};
// 0 for null
namespace seg {
using Value = int;
constexpr int MAX_NUM_NODES = 20'000'010;
int n, id, ls[MAX_NUM_NODES], rs[MAX_NUM_NODES];
Value vals[MAX_NUM_NODES];
void init(int n_) {
n = n_;
id = 1;
}
int newNode() {
assert(id < MAX_NUM_NODES);
const int u = id++;
ls[u] = rs[u] = 0;
vals[u] = Value();
return u;
}
int build(int l, int r) {
const int u = newNode();
if (l + 1 == r) return u;
const int mid = (l + r) / 2;
ls[u] = build(l, mid);
rs[u] = build(mid, r);
return u;
}
int modify(int u, int l, int r, int pos, Value val) {
if (!(l <= pos && pos < r)) return u;
const int v = newNode();
if (l + 1 == r) {
vals[v] = val;
return v;
}
const int mid = (l + r) / 2;
ls[v] = modify(ls[u], l, mid, pos, val);
rs[v] = modify(rs[u], mid, r, pos, val);
vals[v] = vals[ls[v]] + vals[rs[v]];
return v;
}
int modify(int u, int pos, Value val) {
return modify(u, 0, n, pos, val);
}
Value get(int u, int l, int r, int a, int b) {
if (b <= l || r <= a) return 0;
if (a <= l && r <= b) return vals[u];
const int mid = (l + r) / 2;
return get(ls[u], l, mid, a, b) + get(rs[u], mid, r, a, b);
}
Value get(int u, int a, int b) {
return get(u, 0, n, a, b);
}
// min pos s.t. (sum of [0, pos] in v) - (sum of [0, pos] in u) >= tar
int findRight(int u, int v, int l, int r, Value tar) {
if (l + 1 == r) return r;
const int mid = (l + r) / 2;
const Value sumL = vals[ls[v]] - vals[ls[u]];
return (sumL >= tar) ? findRight(ls[u], ls[v], l, mid, tar) : findRight(rs[u], rs[v], mid, r, tar - sumL);
}
int findRight(int u, int v, Value tar) {
if (vals[v] - vals[u] < tar) return n + 1;
return findRight(u, v, 0, n, tar);
}
} // seg
Int sum1(Int n) {
return n * (n + 1) / 2;
}
int N;
char S[500'010];
int Q;
vector<Int> K;
int main() {
for (; ~scanf("%s", S); ) {
N = strlen(S);
scanf("%d", &Q);
K.resize(Q);
for (int q = 0; q < Q; ++q) {
scanf("%lld", &K[q]);
--K[q];
}
const SuffixTree st(S, false);
// cerr<<"graph = "<<st.graph<<endl;
// cerr<<"dis = "<<st.dis<<endl;
// cerr<<"fin = "<<st.fin<<endl;
// cerr<<"sid = "<<st.sid<<endl;
// # occ
vector<Int> dp(st.m, 0);
vector<int> fin(st.m, 0);
for (int i = 0; i < N; ++i) ++dp[st.dis[i]];
for (int j = st.m; --j; ) dp[st.parJ(j)] += dp[j];
vector<Int> ks(st.m + 1, 0);
for (int j = 1; j < st.m; ++j) {
const int u = st.sid[j];
ks[j + 1] = ks[j] + dp[j] * (sum1(st[u].len) - sum1(st[st[u].par].len));
}
// cerr<<"dp = "<<dp<<endl;
// cerr<<"ks = "<<ks<<endl;
seg::init(N);
vector<int> segs(st.m + 1);
segs[0] = seg::build(0, N);
for (int j = 0; j < st.m; ++j) {
const int u = st.sid[j];
segs[j + 1] = (u < N) ? seg::modify(segs[j], u, 1) : segs[j];
}
for (int q = 0; q < Q; ++q) {
const int j = upper_bound(ks.begin(), ks.end(), K[q]) - ks.begin() - 1;
const int u = st.sid[j];
Int lo = st[st[u].par].len, hi = st[u].len;
const Int s0 = sum1(lo);
for (; lo + 1 < hi; ) {
const Int mid = (lo + hi) / 2;
((ks[j] + (sum1(mid) - s0) <= K[q]) ? lo : hi) = mid;
}
const Int tar = K[q] - (ks[j] + (sum1(lo) - s0));
const Int quo = tar / hi;
const Int rem = tar % hi;
// cerr<<"K[q] = "<<K[q]<<": j = "<<j<<", hi = "<<hi<<", quo = "<<quo<<", rem = "<<rem<<endl;
assert(0 <= quo); assert(quo < dp[j]);
Int ans = seg::findRight(segs[st.dis[u]], segs[st.fin[u]], quo + 1) - 1;
ans += rem;
printf("%lld\n", ans + 1);
}
}
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 1ms
memory: 7964kb
input:
pbpbppb 3 1 2 3
output:
2 4 7
result:
ok 3 lines
Test #2:
score: 0
Accepted
time: 1ms
memory: 10012kb
input:
potatop 3 6 30 60
output:
6 3 4
result:
ok 3 lines
Test #3:
score: 0
Accepted
time: 123ms
memory: 11624kb
input:
dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd...
output:
323 644 809 442 923 155 645 275 443 779 441 563 830 495 442 71 699 649 467 204 755 274 394 316 604 211 503 455 764 515 691 541 76 369 695 734 953 440 322 808 693 690 565 116 420 861 179 358 640 687 735 796 581 473 593 859 876 666 596 587 515 616 58 425 470 707 556 735 194 789 819 788 582 666 525 270...
result:
ok 500000 lines
Test #4:
score: -100
Runtime Error
input:
gtgggtgttgggggtgtgggtgttggtttggggtggtgtgggttggtggggtgggttgttggttgggtttggggtgttgggggtgggttttggttgttggtggggttgttggtggtggggtgggttttgggttggtgggtgggtggttgtgttggttttttttgttgggtttgggtgttgttgtggtgggttttggttggggtgttggttggtgtggtgtgggttttggttttttgtttgtggtggtgttttgtttttggtggggtgtttgttgttttggggttggggtgggggttgtgg...
output:
791 715 455 614 589 333 462 296 719 129 801 506 651 668 60 784 111 326 964 356 442 261 328 390 482 320 382 555 729 612 819 154 591 442 890 652 359 652 832 676 670 359 575 146 304 402 71 626 510 209 601 705 29 722 579 502 904 229 712 76 940 897 403 810 506 832 422 183 365 648 659 344 621 478 268 605 ...