2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020)解題報告
2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020)解題報告
B. Reverse Game
大致題意
給出一段01序列,Alice和Bob可以依次輪流對10,110,100,1010進行反轉,使其變成01,011,001,0101。Alice先開始操作,誰先無法操作則對手贏得遊戲
解題思路
可以注意到,所有4種可以反轉的字串,都是將1向串的右側移動,所以結束時,所有的0都在1的左側。繼續觀察操作序列,可以發現每一次操作,都可以使整個串的01逆序對(我們將0在1左側定義為正序)數量減少1或2。所以只要我們統計所有的逆序對,這道題就變成了一個巴什博奕,將逆序對mod 3即可得到答案
E. Divisible by 3
大致題意
給出一個長度為\(n\)的陣列,定義一段子陣列的重量為其中兩兩乘積和。例如有陣列\(b\),對於\(l\)到\(r\)的子陣列,其重量為對於所有\(l \le i < j \le r\),\(b_ib_j\)的乘積。
求給出陣列中重量能被3整除的子陣列數量
\(n\)的範圍:\(1 \le n \le 5\cdot 10^5\)
解題思路
對於\(10^5\)的資料範圍,暴力列舉肯定不行。
定義陣列為\(a\),子陣列字首和為\(sum_i\),子陣列的重量為\(p_i\)
考慮使用dp的思路。對於任意一個子陣列,如果在其之後新增一個新的\(a_i\)
L. Neo-Robin Hood
大致題意
有\(n\)個人,對第\(i\)個人有\(m_i\)的財富,但他還需要\(p_i\)的財富來達到目標,你可以從任意的人手裡搶走\(m_i\)並用來幫助其他人使其完成目標,你搶的人不能超過你所幫助完成目標了的人,求問你能搶的最多的人。
解題思路
⭐參考的優秀部落格SEERC 2020 題解 - -Wallace- - 部落格園 (cnblogs.com)
在選擇時,在選擇(搶)的人數不變時,我們肯定想要搶到手裡的錢儘可能多,這樣才能幫助更多的人,來搶更多的錢。對於任意兩人\(x,y\),如果搶\(x\)幫助\(y\),對手中的錢的貢獻為\(m_x - p_y\),如果搶\(y\)幫助\(x\),那麼對手中錢的貢獻為\(m_y - p_x\),當\(m_y - p_x > m_x - p_y\)時,我們就要反轉策略,來獲得最多的錢。
通過移項,我們將上式變為\(m_y + p_y > m_x + p_x\),我們將每一個人按\(m_i + p_i\)進行降序排序,來獲得最大貢獻。
根據上述性質,我們可以確定,排序後在答案中,幫助的人都排在搶劫的人的後面。我們這時候統計對於每一個分界點,在這個點前面選\(k\)個數,能否大於這個點後面選\(k\)個數
由於選取的人數\(k\)滿足單調(可以搶\(k\)個人,那搶\(k-1\)當人也沒問題),所以\(k\)的值可以使用二分來查詢
在check函式中
用優先佇列來維護對於位置\(i\),在其前面選\(k\)個數能搶到的最多的錢。反方向同樣用一個優先佇列維護幫助\(k\)個人要花的最少的錢。各用一個迴圈即可得到所有的位置的值。
如果對於任意一個位置\(i\)滿足前面的值大於後面的值,說面對當前\(k\)有可行解,返回true
,否則返回false
最終就可以得到最大的\(k\)
M. Mistake
大致題意
給定\(n,k,m\)
給出\(m\)組依賴關係,要求將給出的\(n * k\)個數分為\(k\)組,使每組內的先後順序都滿足前文依賴關係下的拓撲序。
解題思路
遍歷\(n * k\)個數,對於遇到的每一個數,如果這個數此前沒有出現過,那就把他放到第一組,如果出現過,那就放到第 出現的次數 + 1 組裡。
有一個簡單的證明
對於每一個數,如果它所依賴的數出現過,那麼它依賴的數同樣依次被放進了\(1,2,...,k\)中,所以這樣的方法可以必定滿足依賴方法。(所以本題中的依賴方案其實沒什麼用)
程式碼部分
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;
}