Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128)A~C題解
阿新 • • 發佈:2021-10-17
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\)
- 綜上,答案為\(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;
}