# 2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020) shopping spree

## B. Reverse Game

### General meaning

Given a 01 sequence, Alice and Bob can reverse 101101001010 to 010110010101 in turn. Alice starts the operation first. Whoever can't operate first wins the game

### Problem solving ideas

It can be noted that all four reversible strings move 1 to the right of the string, so at the end, all zeros are on the left of 1. Continuing to observe the operation sequence, we can find that each operation can reduce the number of 01 inverse pairs of the whole string (we define 0 as positive order on the left side of 1) by 1 or 2. So as long as we count all the reverse order pairs, this problem becomes a bash game. We can get the answer by reversing the reverse order pair mod 3

## E. Divisible by 3

### General meaning

Give an array with length \ (n \), and define the weight of a sub array as the sum of two products. For example, there is an array \ (B \), and the weight of a subarray from \ (l \) to \ (r \) is the product of all \ (l \ le I < J \ Le r \), \ (b_ib_j \).

Find the number of subarrays in the given array whose weight can be divided by 3

\Range of (n \): \ (1 \le n \le 5\cdot 10^5 \)

### Problem solving ideas

For the data range of \ (10 ^ 5 \), brute force enumeration certainly does not work.

Define the array as \ (a \), the prefix and of the subarray as \ (sum_i \), and the weight of the subarray as \ (p_i \)

Consider the idea of using dp. For any subarray, if a new \ (a_i \) is added after it, the changed weight is equal to \ ((p_{i-1} + sum_{i-1} * a[i]) \), so we can transfer as long as we know \ (p_{i-1} \) and \ (sum_{i-1} \). Moreover, because this problem only requires us to find the number divisible by 3, we can modulo 3 in the process, and then enumerate \ (P {I-1} \) and \ (sum {I-1} \) on each bit. A total of 9 states are transferred

## L. Neo-Robin Hood

### General meaning

There are \ (n \) individuals who have \ (m_i \) wealth to the \ (I \) individual, but they also need \ (p_i \) wealth to achieve their goals. You can take \ (m_i \) from any person and use it to help others achieve their goals. You can't rob more people than the people you help achieve their goals. Ask the person you can rob the most.

### Problem solving ideas

⭐ Excellent blog for reference SEERC 2020 topic solution -- Wallace -- blog Park (cnblogs.com)

When choosing, when the number of people who choose (ROB) remains unchanged, we certainly want to grab as much money as possible, so as to help more people and rob more money. For any two persons \ (x,y \), if we rob \ (x \) to help \ (Y \), the contribution of the opponent's money is \ (m_x - p_y \). If we rob \ (Y \) to help \ (x \), the contribution of the opponent's money is \ (m_y - p_x \). When \ (m_y - p_x > m_x - p_y \), we need to reverse the strategy to get the most money.

By shifting items, we change the above formula into \ (m_y + p_y > m_x + p_x \), and we sort everyone in descending order according to \ (m_i + p_i \) to obtain the maximum contribution.

According to the above properties, we can determine that after ranking, the people who helped ranked behind the robbers in the answer. At this time, we can count whether the number of \ (k \) selected in front of each dividing point is greater than the number of \ (k \) selected after this point

Since the selected number of people \ (K \) is monotonous (you can rob \ (K \) individuals, and it's OK to rob \ (k-1 \) as people), the value of \ (K \) can be found by using two points

In the check function

The priority queue is used to maintain the maximum amount of money that can be grabbed by selecting the number of \ (k \) in front of the location \ (i \). The opposite direction also uses a priority queue to maintain the least money to help \ (k \) individuals. The values of all positions can be obtained by one cycle each.

If the preceding value is greater than the following value for any position \ (i \), it is said that there is a feasible solution to the current \ (k \), return true, otherwise return false

Finally, you can get the maximum \ (k \)

## M. Mistake

### General meaning

Given \ (n,k,m \)

Given the dependency of \ (m \) group, it is required to divide the given number of \ (n * k \) into \ (K \) groups so that the order in each group meets the topological order under the dependency mentioned above.

### Problem solving ideas

Traverse the number of \ (n * k \). For each number encountered, if this number has not appeared before, put it in the first group. If it has, put it in the number of occurrences + 1 group.

There is a simple proof

For each number, if the number it depends on has appeared, the number it depends on is also put into \ (1,2,...,k \) in turn, so such a method can certainly meet the dependent method. (so the dependency scheme in this question is actually useless)

## Code part

#### B

#include<bits/stdc++.h> using namespace std; using ll = long long; void solve() { string s; cin >> s; int n = s.length(); s = " " + s; ll sum = 0; ll cnt = 0; for (int i = 1; i <= n; i++) { if (s[i] == '1') { cnt++; } else { sum += cnt; } } if (sum % 3 == 0) cout << "Bob\n"; else cout << "Alice\n"; } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }

#### E

#include<bits/stdc++.h> using namespace std; using ll = long long; const ll maxn = 5e5; ll dp[maxn+10][3][3]; ll ans = 0; void solve() { ll n; cin >> n; vector<ll> a(n + 1); for (ll i = 1; i <= n; i++) { cin >> a[i]; dp[i][0][a[i] % 3]++; } for (ll i = 1; i <= n; i++) { for (ll j = 0; j < 3; j++) { for (ll k = 0; k < 3; k++) { dp[i][(j + (a[i] * k)) % 3][(k + a[i]) % 3] += dp[i - 1][j][k]; } } } for (ll i = 1; i <= n; i++) { for (ll j = 0; j < 3; j++) ans += dp[i][0][j]; } cout << ans << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }

#### K

#include<bits/stdc++.h> using namespace std; using ll = long long; const ll maxn = 1e5; struct pol { ll m, p; }ps[maxn + 10]; bool cmp(pol a, pol b) { return a.m + a.p > b.m + b.p; } ll n; bool check(ll k) { priority_queue<ll, vector<ll>, greater<ll>> p1; priority_queue<ll, vector<ll>, less<ll>> p2; vector<ll> pre(n + 10); vector<ll> suf(n + 10); ll t = 0; for (ll i = 1; i <= n; i++) { if (p1.size() < k) p1.push(ps[i].m), t += ps[i].m; else if (p1.top() < ps[i].m) { t += ps[i].m - p1.top(); p1.pop(); p1.push(ps[i].m); } pre[i] = t; } t = 0; for (ll i = n; i >= 1; i--) { if (p2.size() < k) p2.push(ps[i].p), t += ps[i].p; else if (p2.top() > ps[i].p) { t += ps[i].p - p2.top(); p2.pop(); p2.push(ps[i].p); } suf[i] = t; } for (ll i = k; i <= n - k; i++) { if (pre[i] - suf[i + 1] >= 0) return true; } return false; } void solve() { cin >> n; for (ll i = 1; i <= n; i++) { cin >> ps[i].m; } for (ll i = 1; i <= n; i++) { cin >> ps[i].p; } sort(ps + 1, ps + 1 + n, cmp); ll l = 1, r = n / 2; ll res = 0; while (l <= r) { ll mid = (l + r) / 2; if (check(mid)) { res = mid; l = mid + 1; } else { r = mid - 1; } } cout << res << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }

#### M

#include<bits/stdc++.h> using namespace std; const int maxn = 5e5; set<int> st[maxn + 10]; void solve() { int n, k, m; cin >> n >> k >> m; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; } for (int i = 1; i <= n * k; i++) { int t; cin >> t; if (st[t].empty()) { cout << 1 << " "; st[t].insert(1); } else{ int tt = *prev(st[t].end()) + 1; cout << tt << " "; st[t].insert(tt); } } } int main() { ios::sync_with_stdio(false); cin.tie(0); solve(); return 0; }