Codeforces Round 585 (Div. 2)

16 September 2019 | duanyll | Tags: OI 题解

一场罕见的国人时间的cf比赛,在学校机房的许多巨佬的带领下总算上蓝了,真是妙不可言。

A. Yellow Cards

最少罚下场:尽量把每个人都罚到只剩一张牌就下场

最多罚下场:先全部罚k值小的一队,再罚大的一对。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
 
const int INF = 0x3f3f3f3f;
 
int main() {
	int a1, a2, k1, k2, n;
	cin >> a1 >> a2 >> k1 >> k2 >> n;
	if (k1 > k2) {
		swap(k1, k2);
		swap(a1, a2);
	}
	int mn, mx;
	if (n <= a1 * (k1 - 1) + a2 * (k2 - 1)) {
		mn = 0;
	} else {
		mn = n - (a1 * (k1 - 1) + a2 * (k2 - 1));
	}
	if (n <= a1 * k1) {
		mx = n / k1;
	} else {
		mx = a1 + (n - a1 * k1) / k2;
	}
	cout << mn << ' ' << mx << endl;
}

B. The Number of Products

从左到右$O(n)$扫一遍,记录遇到的正数负数的数量,代码中cntncntp表示从之前的位置到现在有几个位置开始乘到现在的数是正(负),遇到负数就交换这两个值(想一想为什么)。记得全程int64,身边好多人没开完被叉掉了。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
 
typedef long long int64;
 
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
 
int a[MAXN];
 
#include <cctype>
#include <cstdio>
 
template <typename T = int>
inline T read() {
    T X = 0, w = 0;
    char ch = 0;
    while (!isdigit(ch)) {
        w |= ch == '-';
        ch = getchar();
    }
    while (isdigit(ch)) {
        X = (X << 3) + (X << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -X : X;
}
 
int main() {
	int n = read();
	for (int i = 1; i <= n; i++) {
		int x = read();
		a[i] = (x > 0) ? 1 : -1;
	}
	int64 cntn = 0, cntp = 0;
	int64 ansn = 0, ansp = 0;
	int64 totn = 0, totp = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i] < 0) {
			ansn += cntp;
			ansp += cntn;
			swap(cntn, cntp);
			cntn++;
			totn++;
		} else {
			ansn += cntn;
			ansp += cntp;
			cntp++;
			totp++;
		}
	}
	cout << ansn + totn << ' ' << ansp + totp << endl;
}

C. Swap Letters

首先,本来相等的位置不用管,考虑以下两种不相等的情况

A: ...a...b...     ...b...b...     ...b...a...
      |        ==>      /      ==>
B: ...b...a...     ...a...a...     ...b...a...

因此,方向相同的一对可以一步解决,方向相反的要先一步变成相同的。那么贪就是了,'a'的数量为奇数时无解。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
 
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
 
char a[MAXN], b[MAXN];
 
int main() {
	int n;
	cin >> n >> (a + 1) >> (b + 1);
	int cnta = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i] == 'a') cnta++;
		if (b[i] == 'a') cnta++;
	}
	if (cnta % 2 == 1) {
		cout << -1 << endl;
		return 0;
	}
	vector<int> aabb, abba;
	for (int i = 1; i <= n; i++) {
		if (a[i] == 'a' && b[i] == 'b') {
			aabb.push_back(i);
		} else if (a[i] == 'b' && b[i] == 'a') {
			abba.push_back(i);
		}
	}
	vector<pair<int, int>> ans;
	for (int i = 0; i < aabb.size(); i += 2) {
		if (i + 1 == aabb.size()) break;
		ans.push_back(make_pair(aabb[i], aabb[i + 1]));
	}
	for (int i = 0; i < abba.size(); i += 2) {
		if (i + 1 == abba.size()) break;
		ans.push_back(make_pair(abba[i], abba[i + 1]));
	}
	if (aabb.size() % 2 == 1 && abba.size() % 2 == 1) {
		ans.push_back(make_pair(aabb[aabb.size() - 1], aabb[aabb.size() - 1]));
		ans.push_back(make_pair(aabb[aabb.size() - 1], abba[abba.size() - 1]));
	}
	cout << ans.size() << endl;
	for (int i = 0; i < ans.size(); i++) {
		cout << ans[i].first << ' ' << ans[i].second << endl;
	}
}

再次吐槽辣鸡 dev-cpp,我没有#include <vector>你还能编译?!

D. Ticket Game

简单博弈论,两边问号和相等的值可以约掉(希望不相等的人先走,另一个人复读机就行),剩下的当且仅当数和问号在异侧且两个问号对应一个9时相等的人胜。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
 
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 10;
 
char s[MAXN];
 
int main() {
	int n;
	cin >> n >> s;
	int q = 0, sum = 0;
	for (int i = 0; i < n / 2; i++) {
		if (s[i] == '?')
			q++;
		else 
			sum += s[i] - '0';
	} 
	for (int i = n / 2; i < n; i++) {
		if (s[i] == '?')
			q--;
		else 
			sum -= s[i] - '0';
	} 
	if (q * 9 == -sum * 2) {
		cout << "Bicarp" << endl;
	} else {
		cout << "Monocarp" << endl;
	}
} 

E. Marbles

没有 @ywh666 巨佬提醒我真想不到这东西是个TSP

看到$a_i<20$其实就可以想到是个状压。经过几次模拟可以发现,把$a_i$和$a_j$互相分离的成本是和移动顺序无关的,所以可以抽象成一个TSP,要把20种颜色全部分开,就是要遍历20个点。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
 
typedef long long int64;
 
const int MAXN = 4e5 + 10;
const int MAXA = 25;
const int INF = 0x3f3f3f3f;
 
int a[MAXN];
 
int64 dis[MAXA][MAXA];
int64 dp[(1 << 20) + 10], now[MAXA];
 
int64 tsp() {
	memset(dp, INF, sizeof dp);
	dp[0] = 0;
	for (int i = 0; i < (1 << 20); i++) {
		memset(now, 0, sizeof now);
		for (int j = 1; j <= 20; j++) {
			if (i & (1 << (j - 1))) {
				for (int k = 1; k <= 20; k++) {
					now[k] += dis[j][k];
				}
			}
		}
		for (int j = 1; j <= 20; j++) {
			if (i & (1 << (j - 1))) continue;
			dp[i | (1 << (j - 1))] = min(dp[i | (1 << (j - 1))], dp[i] + now[j]);
		}
	}
	return dp[(1 << 20) - 1];
}
 
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= 20; i++) {
		for (int j = 1; j <= 20; j++) {
			if (i == j) continue;
			int cnt = 0;
			for (int k = n; k >= 1; k--) {
				if (a[k] == i) 
					cnt++;
				else if (a[k] == j) 
					dis[i][j] += cnt;
			}
		}
	}
	cout << tsp() << endl;
}

F题题面太长,看都不想看,结果我那个房就我一个活人,毫无 hack 体验。。。