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