Skip to content

Commit e5627f6

Browse files
committed
Random problems
1 parent 1649ca9 commit e5627f6

9 files changed

+614
-1
lines changed

CEOI/CEOI 14-cake.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
CEOI 2014 Cake
3+
- Let's assume WLOG that b < a in each query
4+
- Also, let d[0] = d[N + 1] = INF
5+
- The answer for a query is simply
6+
min(c : max(d[a : c]) >= max(d[b : a])) - b
7+
- We can use a segtree to store range minimums and walk down it to get c
8+
- To handle an update efficiently, decrement the "rank" of the e - 1 tastiest
9+
pieces and set the
10+
- The "ranks" may become negative, but we only care about relative order
11+
- We can use a std::set to store the order of the cakes
12+
- Complexity: O(max(e) * Q log N)
13+
*/
14+
15+
#include <bits/stdc++.h>
16+
typedef long long ll;
17+
using namespace std;
18+
19+
int d[250001], segtree[2][1000001];
20+
21+
void update(int *seg, int pos, int val, int node, int l, int r) {
22+
if (l == r) seg[node] = val;
23+
else {
24+
int mid = (l + r) / 2;
25+
if (pos > mid) update(seg, pos, val, node * 2 + 1, mid + 1, r);
26+
else update(seg, pos, val, node * 2, l, mid);
27+
seg[node] = max(seg[node * 2], seg[node * 2 + 1]);
28+
}
29+
}
30+
31+
int range_max(int *seg, int a, int b, int node, int l, int r) {
32+
if (l > b || r < a) return 0;
33+
if (l >= a && r <= b) return seg[node];
34+
int mid = (l + r) / 2;
35+
return max(range_max(seg, a, b, node * 2, l, mid), range_max(seg, a, b, node * 2 + 1, mid + 1, r));
36+
}
37+
38+
int walk(int *seg, int threshold, int node, int l, int r) {
39+
if (threshold > seg[node]) return r;
40+
if (l == r) return l - (seg[node] > threshold);
41+
int mid = (l + r) / 2;
42+
if (seg[node * 2] >= threshold) return walk(seg, threshold, node * 2, l, mid);
43+
return walk(seg, threshold, node * 2 + 1, mid + 1, r);
44+
}
45+
46+
int main() {
47+
cin.tie(0)->sync_with_stdio(0);
48+
int n, a;
49+
cin >> n >> a;
50+
vector<int> top_ten;
51+
for (int i = 1; i <= n; i++) {
52+
cin >> d[i];
53+
top_ten.push_back(i);
54+
}
55+
sort(top_ten.begin(), top_ten.end(), [](int A, int B) { return d[A] > d[B]; });
56+
while (top_ten.size() > 10) top_ten.pop_back();
57+
58+
for (int i = a + 1; i <= n; i++) update(segtree[0], i - a, d[i], 1, 1, n - a);
59+
for (int i = a - 1; i; i--) update(segtree[1], a - i, d[i], 1, 1, a - 1);
60+
61+
int q;
62+
cin >> q;
63+
while (q--) {
64+
char c;
65+
cin >> c;
66+
if (c == 'F') {
67+
int b;
68+
cin >> b;
69+
if (b == a) cout << "0\n";
70+
else if (b > a) {
71+
int mx = range_max(segtree[0], 1, b - a, 1, 1, n - a);
72+
cout << walk(segtree[1], mx, 1, 1, a - 1) + b - a << '\n';
73+
} else {
74+
int mx = range_max(segtree[1], 1, a - b, 1, 1, a - 1);
75+
cout << walk(segtree[0], mx, 1, 1, n - a) + a - b << '\n';
76+
}
77+
} else {
78+
int i, e;
79+
cin >> i >> e;
80+
81+
auto it = find(top_ten.begin(), top_ten.end(), i);
82+
if (it != top_ten.end()) top_ten.erase(it);
83+
84+
for (int i = 0; i < e - 1; i++) {
85+
d[top_ten[i]]++;
86+
if (top_ten[i] > a)
87+
update(segtree[0], top_ten[i] - a, d[top_ten[i]], 1, 1, n - a);
88+
else if (top_ten[i] < a)
89+
update(segtree[1], a - top_ten[i], d[top_ten[i]], 1, 1, a - 1);
90+
}
91+
92+
d[i] = d[top_ten[e - 1]] + 1;
93+
if (i > a) update(segtree[0], i - a, d[i], 1, 1, n - a);
94+
else if (i < a) update(segtree[1], a - i, d[i], 1, 1, a - 1);
95+
96+
top_ten.insert(top_ten.begin() + e - 1, i);
97+
if (top_ten.size() > 10) top_ten.pop_back();
98+
}
99+
}
100+
return 0;
101+
}

CEOI/CEOI 14-question.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*
2+
CEOI 2014 Question
3+
- Sperner's theorem
4+
*/
5+
16
#include "question.h"
27
using namespace std;
38

@@ -18,4 +23,4 @@ int Alice(int x,int y){
1823

1924
int Bob(int q,int h){
2025
return sets[q][h - 1];
21-
}
26+
}

JOI/JOI 16-rna.cpp

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
struct TrieNode {
5+
TrieNode *c[4];
6+
int tin, tout;
7+
vector<int> terminal;
8+
vector<tuple<int, int, int>> queries;
9+
unordered_map<int, int> bit;
10+
11+
TrieNode() {
12+
for (int i = 0; i < 4; i++) c[i] = nullptr;
13+
}
14+
};
15+
16+
inline int get_idx(char c) {
17+
if (c == 'A') return 0;
18+
if (c == 'G') return 1;
19+
if (c == 'C') return 2;
20+
return 3;
21+
}
22+
23+
void insert(string &s, TrieNode *node, int i) {
24+
for (char c : s) {
25+
int idx = get_idx(c);
26+
if (!node->c[idx]) node->c[idx] = new TrieNode();
27+
node = node->c[idx];
28+
}
29+
node->terminal.push_back(i);
30+
}
31+
32+
TrieNode *retrieve(string &s, TrieNode *node) {
33+
for (char c : s) {
34+
int idx = get_idx(c);
35+
if (!node->c[idx]) return nullptr;
36+
node = node->c[idx];
37+
}
38+
return node;
39+
}
40+
41+
int n, m, label[100001];
42+
vector<int> comp;
43+
44+
void euler_tour(TrieNode *node, int &timer) {
45+
node->tin = ++timer;
46+
if (node->terminal.size()) {
47+
for (int i : node->terminal) label[i] = timer;
48+
comp.push_back(timer);
49+
}
50+
for (int i = 0; i < 4; i++)
51+
if (node->c[i]) euler_tour(node->c[i], timer);
52+
node->tout = timer;
53+
}
54+
55+
int ans[100001];
56+
57+
void merge(TrieNode *A, TrieNode *B) {
58+
if (A->bit.size() > B->bit.size()) swap(A->bit, B->bit);
59+
for (pair<int, int> i : A->bit) B->bit[i.first] += i.second;
60+
}
61+
62+
int find_lb(int val) {
63+
return lower_bound(comp.begin(), comp.end(), val) - comp.begin() + 1;
64+
}
65+
66+
int find_ub(int val) {
67+
return upper_bound(comp.begin(), comp.end(), val) - comp.begin();
68+
}
69+
70+
void update(unordered_map<int, int> &bit, int pos, int val) {
71+
for (; pos <= comp.size(); pos += pos & -pos) bit[pos] += val;
72+
}
73+
74+
int query(unordered_map<int, int> &bit, int l, int r) {
75+
int ans = 0;
76+
for (; r; r -= r & -r) ans += bit[r];
77+
for (l--; l; l -= l & -l) ans -= bit[l];
78+
return ans;
79+
}
80+
81+
void traverse(TrieNode *node) {
82+
for (int i = 0; i < 4; i++)
83+
if (node->c[i]) {
84+
traverse(node->c[i]);
85+
merge(node->c[i], node);
86+
}
87+
for (int i : node->terminal) update(node->bit, find_lb(label[i]), 1);
88+
89+
for (auto i : node->queries) {
90+
int idx, l, r;
91+
tie(idx, l, r) = i;
92+
ans[idx] = query(node->bit, find_lb(l), find_ub(r));
93+
}
94+
}
95+
96+
int main() {
97+
cin.tie(0)->sync_with_stdio(0);
98+
cin >> n >> m;
99+
TrieNode *pref = new TrieNode(), *suff = new TrieNode();
100+
for (int i = 1; i <= n; i++) {
101+
string s;
102+
cin >> s;
103+
insert(s, pref, i);
104+
reverse(s.begin(), s.end());
105+
insert(s, suff, i);
106+
}
107+
108+
int timer = 0;
109+
euler_tour(pref, timer);
110+
111+
for (int i = 1; i <= m; i++) {
112+
string s, t;
113+
cin >> s >> t;
114+
reverse(t.begin(), t.end());
115+
TrieNode *s_node = retrieve(s, pref), *t_node = retrieve(t, suff);
116+
if (s_node && t_node)
117+
t_node->queries.push_back({i, s_node->tin, s_node->tout});
118+
}
119+
120+
traverse(suff);
121+
for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
122+
}

JOI/JOI 19-cake.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
JOISC 2019 Cake 3
3+
- Sort the cakes by colour
4+
- Ans = max(max(2C[j] + (M best cakes in [j, i])) - 2C[i])
5+
- The optimal j for each i is non-decreasing, so we can use D&C DP to solve this
6+
- We can walk down a segment tree to find (M best cakes in [j, i])
7+
- Complexity: O(N log^2 N)
8+
*/
9+
10+
#include <bits/stdc++.h>
11+
typedef long long ll;
12+
using namespace std;
13+
14+
const ll INF = 1e18;
15+
16+
int n, m;
17+
pair<ll, ll> cake[200001];
18+
ll dp[200001];
19+
20+
void solve(int l, int r, int lopt, int ropt) {
21+
if (l > r) return;
22+
23+
int mid = (l + r) / 2;
24+
int opt = -1;
25+
26+
// Do stuff
27+
28+
dp[mid] = -INF;
29+
for (int i = min(mid - m + 1, ropt); i >= lopt; i--) {
30+
ll pot = 2 * cake[i].second + m_best();
31+
if (pot > dp[mid])
32+
dp[mid] = pot, opt = i;
33+
toggle_cake(i, true);
34+
}
35+
dp[mid] -= 2 * cake[mid].second;
36+
37+
// Toggle the other cakes
38+
39+
solve(l, mid - 1, lopt, opt);
40+
solve(mid + 1, r, opt, ropt);
41+
}
42+
43+
int main() {
44+
cin.tie(0)->sync_with_stdio(0);
45+
cin >> n >> m;
46+
for (int i = 1; i <= n; i++) cin >> cake[i].first >> cake[i].second;
47+
solve(m, n, 1, n - m + 1);
48+
cout << *max_element(dp + m, dp + n + 1);
49+
return 0;
50+
}

POI/POI 18-polynomial.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
POI 2018 Polynomial
3+
- We use the idea behind the FFT to solve this problem
4+
- Let dft(k, idx, W) = {W(q^ki) % M : i from 0 to N / k}
5+
- Our answer is dft(1, 0, W)
6+
- If k == N, then dft(k, idx, W) = A[idx]
7+
- Otherwise, W(x) = W_even(x^2) + x * W_odd(x^2)
8+
- We can find ans = dft(k, idx, W) using even = dft(2k, idx, W_even) and odd = dft(2k, idx | k, W_odd)
9+
- Case 1: i < N / 2k
10+
- ans[i] = W(q^ki) % M
11+
= (W_even(q^2ki) + q^ki * W_odd(q^2ki)) % M
12+
= (even[i] + q^ki * odd[i]) % M
13+
- Case 2: i >= N / 2k
14+
- Write i as N / 2k + j
15+
- Note that j = i % (N / 2k)
16+
- ans[i] = W(q^(N / 2 + kj)) % M
17+
= (W_even(q^N * q^2kj) + q^ki * W_odd(q^N * q^2kj)) % M
18+
= (W_even(q^2kj) + q^ki * W_odd(q^2kj)) % M (since q^N % N = 1)
19+
= (even[j] + q^ki * odd[j]) % M
20+
- Putting the two cases together, we get
21+
ans[i] = (even[i % (N / 2k)] + q^ki * odd[i % (N / 2k)]) % M
22+
- Each layer of recursion takes O(N) time to compute and there are O(log N) layers,
23+
so the time complexity is O(N log N)
24+
*/
25+
26+
#include <bits/stdc++.h>
27+
typedef long long ll;
28+
using namespace std;
29+
30+
int n;
31+
ll m, q, a[1 << 20], q_pow[1 << 20];
32+
33+
vector<ll> dft(int k = 1, int idx = 0) {
34+
if (k == n) return {a[idx]};
35+
else {
36+
vector<ll> even = dft(k * 2, idx);
37+
vector<ll> odd = dft(k * 2, idx | k);
38+
39+
int split = n / k / 2;
40+
vector<ll> ans;
41+
for (int i = 0; i < 2 * split; i++)
42+
ans.push_back((even[i % split] + q_pow[k * i] * odd[i % split] % m) % m);
43+
return ans;
44+
}
45+
}
46+
47+
int main() {
48+
cin.tie(0)->sync_with_stdio(0);
49+
cin >> n >> m >> q;
50+
for (int i = 0; i < n; i++) cin >> a[i];
51+
52+
q_pow[0] = 1;
53+
for (int i = 1; i < n; i++) q_pow[i] = q * q_pow[i - 1] % m;
54+
55+
vector<ll> ans = dft();
56+
ll tot = 0;
57+
for (ll i : ans) tot = (tot + i) % m;
58+
cout << tot << '\n';
59+
for (int i = 1; i < n; i++) cout << ans[i] << ' ';
60+
cout << ans[0];
61+
return 0;
62+
}

0 commit comments

Comments
 (0)