Educational Codeforces Round 91 (Rated for Div. 2)
目錄
Educational Codeforces Round 91 (Rated for Div. 2)
待補
- E
- F
- G
1. 題目分析
- A:思維
- B: 思維
- C: 貪心
- D: 思維+分類討論
2. 題解
A. Three Indices
題意: 給定t個樣例,每個樣例給定一個n,而後給出n個數字,要求判斷是否存在3個數字ai,aj,ak,滿足i < j < k, 且aj > ai, aj > ak。如果存在輸出YES,而後輸出i, j, k;不存在輸出NO。T ~ 200, n ~ 1000
題解:
程式碼:
#include <bits/stdc++.h> using namespace std; int const N = 1e3 + 10; int a[N], n, T, le[N], ri[N]; int main() { cin >> T; while (T--) { memset(ri, -1, sizeof ri); memset(le, -1, sizeof le); cin >> n; for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); int minv1 = 1e9 + 10, minv2 = 1e9 + 10, minid1 = -1, minid2 = -1; for (int i = 1; i <= n; ++i) { if (minv1 < a[i]) le[i] = minid1; if (a[i] < minv1) { minv1 = a[i]; minid1 = i; } } for (int i = n; i >= 1; --i) { if (minv2 < a[i]) ri[i] = minid2; if (a[i] < minv2) { minv2 = a[i]; minid2 = i; } } int flg = 0; for (int i = 2; i <= n; ++i) { if (le[i] != -1 && ri[i] != -1) { cout << "YES\n"; cout << le[i] << " " << i << " " << ri[i] << endl; flg = 1; break; } } if (flg == 1) continue; cout << "NO\n"; } return 0; }
B. Universal Solution
題意: 現在要和機器人玩猜拳,機器人的出拳方式已經知道了。人的出拳方式需要確定,同時從什麼時候出拳也需要確定,請找到一種出拳方式,使得人無論是在什麼時候出拳,勝利的概率都能最大。給出t個測試樣例,每個測試樣例給出一個長度為n的字串,表示機器人的出拳方式。t ~ 1000, n ~ 2e5
程式碼
題解: 無論是從什麼時候出拳都要保證勝率最大,因此只需要統計當前機器人出拳的最多的那個是什麼即可,而後每次都成勝最多的那個即可。
程式碼:
#include <bits/stdc++.h> using namespace std; int T; int main() { int R = 0, S = 0, P = 0; cin >> T; string s; while (T--) { cin >> s; R = 0, S = 0, P = 0; for (int i = 0; i < s.size(); ++i) { if (s[i] == 'R' ) R++; else if (s[i] == 'S') S++; else if (s[i] == 'P') P++; } int maxv = max(R, max(S, P)); if (R == maxv) { for (int i = 0; i < s.size(); ++i) cout << 'P'; } else if (S == maxv) { for (int i = 0; i < s.size(); ++i) cout << 'R'; } else if (P == maxv) { for (int i = 0; i < s.size(); ++i) cout << 'S'; } cout << endl; } return 0; }
C. Make It Good
題意: 現在有n個同學,希望把這n個同學分成很多的非空的團隊,每個團隊的能力值=團隊中能力值最低的同學的能力值*團隊的人數,問最多能夠組成多少個這樣的團隊。給定t個測試樣例,每個測試樣例給出n和k,n表示有n個同學,k表示團隊的最小能力值。而後給出n個數字表示每個同學的能力值。
題解: 考慮貪心處理,先把同學按照能力值按照從小到大排序。而後從大到小掃描,如果當前同學的能力值大於k,則可以單獨組成團隊;如果小於k,那麼考慮增加團隊的人數;O(n)掃描即可
程式碼:
#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
int T, a[N], n, x;
int main() {
cin >> T;
while (T--) {
cin >> n >> x;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
int res = 0, mul = 1e9, cnt = 0;
for (int i = n; i >= 1; --i) {
if (a[i] >= x) {
res ++;
// cout << "i:" << i << endl;
continue;
}
else {
mul = a[i];
cnt++;
if (mul * cnt >= x) {
res ++;
// cout << "i:" << i << endl;
cnt = 0;
}
}
}
cout << res << endl;
}
return 0;
}
D. Berserk And Fireball
題意: 現在有兩排戰士,第一排戰士有n個,對第一排戰士進行消滅一定數目後將會變成第二排戰士。消滅戰士的方式有兩種,第一種是選擇連續k個戰士,將其消滅,這將消耗x元;第二種是選擇兩個相鄰的戰士,消滅其中較小的那個戰士,這將消耗y元。第一行給定n和k,第二行給定x、k和y,第三行給出第一排戰士的編號,第四行給出第二排戰士的標號。大於最小的花費,如果不存在輸出-1.
題解: 題目給出了第二排戰士,所有隻需要按照第二排戰士的的最後結果去匹配第一行戰士,就可以得到很多的分段,然後計算是否可以刪除這些分段,如果能夠刪除,求出最小的花費即可,需要分類討論。
如果序列 b 中元素的出現順序與 a 不一致,則無解。
否則根據 b 將 a 分割為一個個區間,對每一個區間進行單獨操作。
對於一個長度小於 k 的區間:
- 如果區間最大值大於兩端的分割點,則無解
- 否則花費為 size×y
對於一個長度大於等於 k 的區間:
- 如果區間最大值大於兩端的分割點,則必須使用一次操作一
- 如果操作一花費較小,花費為 ⌊sizek⌋×x+size % k×y
- 如果操作二花費較小,花費為 x+(size−k)×y
- 如果區間最大值小於兩端的分割點,則可不必使用操作一
- 如果操作一花費較小,花費為 ⌊sizek⌋×x+size % k×y
- 如果操作二花費較小,花費為 size×y
程式碼:
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int main() {
ll n, m, x, k, y; cin >> n >> m >> x >> k >> y;
int a[n] = {};
int pos[n] = {};
for (int i = 0; i < n; i++) {
cin >> a[i];
--a[i];
pos[a[i]] = i;
}
int b[m] = {};
int mx_pos = 0;
bool skip[n] = {}; //記錄在 a 中的分割點
for (int i = 0; i < m; i++) {
cin >> b[i];
--b[i];
if (pos[b[i]] < mx_pos) {
cout << -1 << "\n";
return 0;
} else mx_pos = pos[b[i]];
skip[b[i]] = true;
}
vector<vector<int>> v; //儲存每個區間
vector<pair<int, int>> border; //儲存每個區間兩端的分割點
vector<int> t; //每個區間
int l = -1, r = -1; //左右端點
for (int i = 0; i < n; i++) {
if (skip[a[i]]) { //如果遇到區間分割點
if (l == -1 and r == -1) { //第一個區間只有右端點
r = a[i];
} else { //之後區間的左端點為上一個區間的右端點
l = r;
r = a[i];
}
if (t.size() > 0) {
v.push_back(t);
border.emplace_back(l, r);
t.clear();
}
continue;
}
t.push_back(a[i]);
}
if (t.size() > 0) {
l = r;
v.push_back(t);
border.emplace_back(l, -1);
t.clear();
}
ll ans = 0;
for (int i = 0; i < v.size(); i++) {
bool seg_mx = *max_element(v[i].begin(), v[i].end()) > max(border[i].first, border[i].second);
if (v[i].size() < k) {
if (seg_mx) {
cout << -1 << "\n";
return 0;
}
ans += v[i].size() * y;
} else {
if (seg_mx)
ans += min(x + (v[i].size() - k) * y, v[i].size() / k * x + v[i].size() % k * y);
else
ans += min(v[i].size() * y, v[i].size() / k * x + v[i].size() % k * y);
}
}
cout << ans << "\n";
}