A - Gold and Silver

对于每两次交易来说,获得的黄金数等于\(\frac {xa_{i}} {a_{i + 1}}\),也就是保证\(a_{i} > a_{i + 1}\)这两次交易一定可以获益。但是题目问的是获得黄金数量的最大值,也就是说交易的次数一定为偶数次才能符合题意。那么我们每次进行两次交易,同时找到一个相邻非递增数对和相邻非递减数对标记,输出即可

// Author: a1xt_CN
// Problem: A - Gold and Silver
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128)
// URL: https://atcoder.jp/contests/arc128/tasks/arc128_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-10-16 20:00:08

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 200010;
int a[N];
bool vis[N];
int main() {
	int n;
	cin >> n;
	for (int i = 1;i <= n;++i) {
		cin >> a[i];
	}
	for (int i = 1;i <= n;++i) {
		while (i < n && a[i+1] >= a[i])
			++i;
		if (i < n)
			vis[i] = 1;
		else break;
		while (i < n && a[i] >= a[i+1])
			++i;
		vis[i] = 1;
	}
	for (int i = 1;i <= n;++i) {
		cout << vis[i] << ' ';
	}
	cout << endl;
	return 0;
}

B - Balls of Three Colors

这题很有意思。首先考虑一定可以的情况,那就是有两种或者三种颜色的球数目相同。这样我们可以将两种个数相同的球变为第三种颜色的球,变换次数即相同颜色的球的对数。

除此之外就是两两不同的情况。我们可以发现,如果将两种颜色球变为另外一种颜色的球,那么被变颜色的球和变颜色的球个数差会变化3。如果我们要将两两不同的情况变为上一种一定可以的情况,当且仅当存在两种颜色的球的个数之差是三的倍数。此条件不满足,任意两种颜色的球的个数都不会相等,因此一定无解;

为了表示方便,我们设各种球的个数分别为\(r,g,b,且3|(r - b)\),最后我们要将所有颜色的球变为\(G\)。分两种情况讨论:

  • \(g ≥ (r - b) / 3\),这样我们每次减少一个\(r\)和一个\(g\),总共减少\((r - b)/3\)\(r\)\(g\),使得\(r\)\(b\)全部变为\(b + 2(r - b)/3\),注意此时\(g≥0\)。所以接下来只要每次减少一个\(r\)和一个\(b\),总共减少\(b+2(r-b)/3\)次就可以将所有的球颜色变为\(G\)。答案为\(b + 3(r-b)/3 = r\)
  • \(g<(r-b)/3\),如果仍然按照上种方法做,会导致颜色为\(G\)的球不够用。但此种情况并非无解。首先我们利用比较多的\(r\)\(b\)尽可能的转为\(g\),转\(b\)次。此时\(b=0,g = g+2b,r = r-b\),再将一个\(g\)和一个\(r\)转为两个\(b\),此时\(b = 2,g = g + 2b - 1,r = r- b - 1\),再将两个\(b\)全部转为\(g\),此时\(b = 0,g = g + 2b + 3,r = r - b - 3\),可以发现,经过这三次操作,\(g\)变多,\(r\)减少三个依然是三的倍数,因此重复上次操作即可将所有球转为\(G\)。答案为\(b + (r - b) / 3 \times 3 = r\)
  • 综上,答案为\(r\)

注意,因为要求最小值,所以要对所有可能取\(min\)

// Author: a1xt_CN
// Problem: B - Balls of Three Colors
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128)
// URL: https://atcoder.jp/contests/arc128/tasks/arc128_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-10-16 20:00:12

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 200010;

int main() {
	int t;cin >> t;
	while (t--) {
		int r,g,b;
		cin >> r >> g >> b;
		if (r == g) {
			cout << r << endl;
			continue;
		}else if (g == b) {
			cout << g << endl;
			continue;
		}else if (r == b) {
			cout << r << endl;
			continue;
		}
		bool f = 0;
		int res = 1e9;
		if (abs(r - g) % 3 == 0) {
			res = min(res,max(r,g));
			f = 1;
		}
		if (abs(b - g) % 3 == 0) {
			res = min(res,max(b,g));
			f = 1;
		}
		if (abs(r - b) % 3 == 0) {
			res = min(res,max(r,b));
			f = 1;
		}
		if (!f)	puts("-1");
		else cout << res << endl;
	}
	return 0;
}

C - Max Dot

结论题。结论为,从末尾向前找的子序列中,将价值最大(价值指序列的和与序列长度的比值)的序列分配为当前可分配的最大值(即\(min(M,S/s)\),\(S\)为分配剩余的总和,\(s\)为当前序列的长度,\(M\)为限制的最大值),其余均为0;

证明:[参见官方题解](Editorial - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128))

// Author: a1xt_CN
// Problem: C - Max Dot
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128)
// URL: https://atcoder.jp/contests/arc128/tasks/arc128_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-10-16 20:00:16

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 5010;

int a[N];
int main() {
	int n,m,S;
	cin >> n >> m >> S;
	for (int i = 0;i < n;++i) {
		cin >> a[i];
	}
	double ans = 0;
	int p = n;
	while (p != 0 && S > 0) {
		int s = 0;ll sum = 0;
		int u = p - 1;
		double R = 0;
		for (int i = p - 1;i >= 0;--i) {
			s += 1,sum += a[i];
			if ((double)sum / s > R) {
				R = (double) sum / s;
				u = i;
			}
		}
		//cout <<"? "<< u << endl;
		s = sum = 0;
		for (int i = u;i < p;++i) {
			s += 1,sum += a[i];
		}
		double cnt = min((double) m,(double) S / s);
		ans += sum * cnt;
		S -= cnt * s;
		p = u;
	}
	printf("%.10lf\n",ans);
	return 0;
}