Skip to content

Commit 134d97c

Browse files
committed
Chinese problems
1 parent 1872f5e commit 134d97c

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

Atcoder/ABC 141-F.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Reference: https://math.stackexchange.com/questions/48682/maximization-with-xor-operator
2+
3+
#include <bits/stdc++.h>
4+
typedef long long ll;
5+
using namespace std;
6+
7+
ll a[100001], all_xor = 0;
8+
9+
int main() {
10+
cin.tie(0)->sync_with_stdio(0);
11+
int n;
12+
cin >> n;
13+
for (int i = 0; i < n; i++) {
14+
cin >> a[i];
15+
all_xor ^= a[i];
16+
}
17+
for (int i = 0; i < n; i++) a[i] &= ~all_xor;
18+
19+
for (int i = 59, j = 0; ~i; i--) {
20+
int k = j;
21+
// Find any a[k] with the i-th bit as 1
22+
while (k < n && !(a[k] & (1ll << i))) k++;
23+
if (k == n) continue;
24+
// "Pivot" to make the i-th bit of a[j] also 1
25+
if (k > j) a[j] ^= a[k];
26+
k = j + 1;
27+
while (k < n) {
28+
// If a[k] has the i-th bit as 1, then it gets XORed with a[j]
29+
// Otherwise, it stays the same
30+
a[k] = min(a[k], a[k] ^ a[j]);
31+
k++;
32+
}
33+
j++;
34+
}
35+
ll ans = 0;
36+
// Now that the position of the most significant bit is different for each a[i],
37+
// we can greedily take the max subset XOR
38+
for (int i = 0; i < n; i++) ans = max(ans, ans ^ a[i]);
39+
cout << ans * 2 + all_xor;
40+
return 0;
41+
}

NOI.cn/NOI 09-treap.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
NOI.cn 2009 Modified Treap
3+
- First, sort the nodes by their keys
4+
- Let dp[l][r][w] = Min cost to construct a BST with the nodes [l, r]
5+
such that the root's priority is at least w
6+
= min(
7+
{ dp[l][m - 1][w] + dp[m + 1][r][w] + k : m from l to r },
8+
{ dp[l][m - 1][p[m]] + dp[m + 1][r][p[m]] : m from l to r and p[m] >= w }
9+
) + (Sum of frequencies of nodes [l, r])
10+
- Using memoization, this runs in O(N^4) time because w in our DP array
11+
can only take on O(N) values (kinda like coordinate compression)
12+
- The first case of our DP transition is from changing the priority of node m
13+
- The second case of our DP transition is from not changing the priority
14+
because we don't have to
15+
- Note that we still need the other case because it may not be optimal not
16+
to change the priority even if we don't have to
17+
- Complexity: O(N^4)
18+
*/
19+
20+
#include <bits/stdc++.h>
21+
using namespace std;
22+
23+
int n;
24+
array<int, 3> node[71];
25+
int k, pref[71];
26+
unordered_map<int, int> dp[71][71];
27+
28+
int solve(int l, int r, int mn) {
29+
if (l > r) return 0;
30+
if (l == r) return k * (node[l][1] < mn) + node[l][2];
31+
if (dp[l][r].count(mn)) return dp[l][r][mn];
32+
int ans = INT_MAX;
33+
for (int i = l; i <= r; i++) {
34+
ans = min(ans, solve(l, i - 1, mn) + solve(i + 1, r, mn) + k);
35+
if (node[i][1] >= mn)
36+
ans = min(ans, solve(l, i - 1, node[i][1]) + solve(i + 1, r, node[i][1]));
37+
}
38+
return dp[l][r][mn] = ans + pref[r] - pref[l - 1];
39+
}
40+
41+
int main() {
42+
cin.tie(0)->sync_with_stdio(0);
43+
cin >> n >> k;
44+
for (int i : {0, 1, 2})
45+
for (int j = 1; j <= n; j++) cin >> node[j][i];
46+
sort(node + 1, node + n + 1);
47+
for (int i = 1; i <= n; i++) pref[i] = pref[i - 1] + node[i][2];
48+
cout << solve(1, n, 0);
49+
return 0;
50+
}

NOI.cn/NOI 10-superpiano.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
NOI.cn 2010 Super Piano
3+
- First, build a prefix sum array of the note values
4+
- The best chord we can make starting on note i has value
5+
max(pref[j] : j from i + l to i + r) - pref[i - 1]
6+
- This is a range query, so we can use a segment tree to
7+
handle it and remove that optimal position after using it
8+
- However, there can be multiple different starting notes,
9+
so we can't just straight-up remove values from the segtree,
10+
since other starting positions could potentially depend on
11+
those
12+
- To address this, simply use a persistent segtree so that
13+
each starting position has its own segtree
14+
- There are O(K + N) nodes because we update K times
15+
- Complexity: O((K + N) log N)
16+
*/
17+
18+
#include <bits/stdc++.h>
19+
typedef long long ll;
20+
using namespace std;
21+
22+
struct Node {
23+
pair<int, int> val;
24+
Node *lc, *rc;
25+
26+
Node(pair<int, int> _val) : val(_val), lc(nullptr), rc(nullptr) {}
27+
28+
Node(Node *_lc, Node *_rc) : lc(_lc), rc(_rc), val({INT_MIN, -1}) {
29+
if (lc) val = max(val, lc->val);
30+
if (rc) val = max(val, rc->val);
31+
}
32+
} * persist_roots[500001];
33+
34+
int n, x, y, k, pref[500001];
35+
36+
Node *build(int l = 1, int r = n) {
37+
if (l == r) return new Node({pref[l], l});
38+
int mid = (l + r) / 2;
39+
return new Node(build(l, mid), build(mid + 1, r));
40+
}
41+
42+
pair<int, int> query(Node *node, int a, int b, int l = 1, int r = n) {
43+
if (!node || r < a || l > b) return {INT_MIN, -1};
44+
if (l >= a && r <= b) return node->val;
45+
int mid = (l + r) / 2;
46+
return max(query(node->lc, a, b, l, mid),
47+
query(node->rc, a, b, mid + 1, r));
48+
}
49+
50+
Node *update(Node *node, int pos, int l = 1, int r = n) {
51+
if (l == r) return nullptr;
52+
int mid = (l + r) / 2;
53+
if (pos > mid) return new Node(node->lc, update(node->rc, pos, mid + 1, r));
54+
return new Node(update(node->lc, pos, l, mid), node->rc);
55+
}
56+
57+
int main() {
58+
cin.tie(0)->sync_with_stdio(0);
59+
cin >> n >> k >> x >> y;
60+
for (int i = 1; i <= n; i++) {
61+
int a;
62+
cin >> a;
63+
pref[i] = pref[i - 1] + a;
64+
}
65+
Node *init_root = build();
66+
for (int i = 1; i <= n - x + 1; i++) persist_roots[i] = init_root;
67+
68+
priority_queue<pair<int, int>> pq;
69+
for (int i = 1; i <= n - x + 1; i++) {
70+
pair<int, int> res = query(persist_roots[i], i + x - 1, i + y - 1);
71+
pq.push({res.first - pref[i - 1], i});
72+
persist_roots[i] = update(persist_roots[i], res.second);
73+
}
74+
ll ans = 0;
75+
while (k--) {
76+
int v, i;
77+
tie(v, i) = pq.top();
78+
pq.pop();
79+
ans += v;
80+
pair<int, int> res = query(persist_roots[i], i + x - 1, i + y - 1);
81+
pq.push({res.first - pref[i - 1], i});
82+
persist_roots[i] = update(persist_roots[i], res.second);
83+
}
84+
cout << ans;
85+
return 0;
86+
}

0 commit comments

Comments
 (0)