ABC 437
Table of Contents
https://atcoder.jp/contests/abc437
A. Feet
https://atcoder.jp/contests/abc437/tasks/abc437_a
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll A, B;
cin >> A >> B;
cout << A * 12 + B << endl;
}
B. Tombola
https://atcoder.jp/contests/abc437/tasks/abc437_b
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll H, W, N;
cin >> H >> W >> N;
vvll grid(H, vll(W));
rep(i, H) rep(j, W) {
cin >> grid[i][j];
}
ll ans = 0;
set<ll> B;
rep(i, N) {
ll x;
cin >> x;
B.insert(x);
}
rep(_, N) {
rep(i, H) {
ll tmp = 0;
rep(j, W) {
if (B.count(grid[i][j])) tmp++;
}
chmax(ans, tmp);
}
}
cout << ans << endl;
}
C. Reindeer and Sleigh 2
https://atcoder.jp/contests/abc437/tasks/abc437_c
解説 AC
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
auto cal = []() -> void {
ll N;
cin >> N;
vll W(N), P(N);
rep(i, N) cin >> W[i] >> P[i];
ll psum = accumulate(all(P), 0ll);
vll sums;
rep(i, N) sums.push_back(W[i] + P[i]);
sort(all(sums));
ll ans = 0;
ll sum = 0;
for (auto x : sums) {
if (psum >= sum + x) {
sum += x;
ans++;
}
}
cout << ans << endl;
};
int t;
cin >> t;
rep(i, t) cal();
}
D. Sum of Differences
https://atcoder.jp/contests/abc437/tasks/abc437_d
特定の $B_j$ にだけ注目する. $S = \{ x | x \in A \wedge x \geq B_j\}$, $T = \{ x | x \in A \wedge x < B_j\}$ とすると,
\begin{align*} \sum_{i} |A_i - B_j| &= \sum_{x \in S} (x - B_j) + \sum_{x \in T} (B_j - x) \\ &= \left\{ \left( \sum_{x \in S} x \right) - B_j |S| \right\} + \left\{ B_j |T| - \sum_{x \in T} x \right\} \\ \end{align*}
となる。よって $A$ をソートし, 累積和を取っておけば, 各 $B_j$ について二分探索で $S, T$ の境界を求め, 上記の式を計算できる。
template <typename T>
struct Cumsum {
vector<T> data;
Cumsum(vector<T> v) {
int n = v.size();
data.resize(n + 1);
data[0] = 1;
rep(i, n) {
data[i + 1] = data[i] + v[i];
}
}
// sum of range [l,r)
ll sum(int l, int r) {
return data[r] - data[l];
}
};
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll N, M;
cin >> N >> M;
vll A(N), B(M);
rep(i, N) cin >> A[i];
rep(i, M) cin >> B[i];
sort(all(A));
sort(all(B));
mint ans = 0;
Cumsum cumsuma(A), cumsumb(B);
for (ll b : B) {
auto it = lower_bound(all(A), b);
ll d = it - A.begin();
ans += cumsuma.sum(d, N) - b * (A.end() - it);
ans += b * d - cumsuma.sum(0, d);
}
cout << ans.val() << endl;
}
E. Sort Arrays
https://atcoder.jp/contests/abc437/tasks/abc437_e
Trie 木を構築する。各ノードにはそのノードを終点とする数列の番号を格納していく。 あとは DFS を使って順に数列番号を取り出せば良い。

struct Node {
vll ids;
map<ll, Node*> next_node;
};
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
ll N;
cin >> N;
vector<Node*> nodes(N + 1, new Node());
rep(i, N) {
int id = i + 1;
ll x, y;
cin >> x >> y;
Node* node = nodes[x];
auto& next_node = node->next_node;
if (next_node.count(y)) {
next_node[y]->ids.push_back(id);
} else {
// Node tmp_node; という定義方法だとスコープを抜けた段階でデータが捨てられてしまうのでヒープ領域に確保する必要がある
Node* tmp_node = new Node();
tmp_node->ids.push_back(id);
next_node[y] = tmp_node;
}
nodes[id] = next_node[y];
}
vll ans;
auto dfs = [&](auto dfs, Node* now) -> void {
for (auto x : now->ids) ans.push_back(x);
for (auto [k, v] : now->next_node) dfs(dfs, v);
};
dfs(dfs, nodes[0]);
print(ans);
}
pointer を使わない実装
struct Trie {
vector<map<int, int>> to;
vint node_id; // node_id[i]: 数列 i の末端の node id
vvint ids; // ids[i]: node_id i を末端とする数列の id
Trie() {
to.resize(1);
ids.resize(1);
node_id.resize(1, 0);
}
void add(int x, int y, int id) {
int xnode = node_id[x];
if (!to[xnode].count(y)) {
int n = to.size();
to[xnode][y] = n;
to.push_back(map<int, int>());
ids.push_back(vint({id}));
node_id.push_back(n);
return;
}
auto& nid = to[xnode][y];
node_id.push_back(nid);
ids[nid].push_back(id);
}
void collect(int now, vint& ans) {
for (int x : ids[now]) ans.push_back(x);
for (auto [_, v] : to[now]) {
collect(v, ans);
}
}
};
void solve() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
Trie trie;
int N;
cin >> N;
rep(i, N) {
int x, y;
cin >> x >> y;
trie.add(x, y, i + 1);
}
vint ans;
trie.collect(0, ans);
print(ans);
}
F. Manhattan Christmas Tree 2
https://atcoder.jp/contests/abc437/tasks/abc437_f