1. 程式人生 > 其它 >2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020)解題報告

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\)

,那麼變化後的重量等於\((p_{i-1} + sum_{i-1} * a[i])\),所以其實只要知道\(p_{i-1}\)\(sum_{i-1}\),我們就可以進行轉移。而且因為這道題只要求我們求被3整除的數量,所以就可以在過程中進行對3取模,然後在每一位上\(0 - 3\)列舉\(p_{i-1}\)\(sum_{i-1}\),一共9個狀態進行轉移


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;
}