Educational Codeforces Round 91 (Rated for Div. 2)
待补c++
- 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
题解: 先正着扫一遍,判断当前数字前最小的那个数字下标;再倒着扫一遍,判断当前数字后最大的数字的下标。然后正着扫一遍判断当前数字前是否有比它小的数字,当前数字后是否有比它大的数字便可。O(n)
代码:
测试
#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
代码
题解: 不管是从何时出拳都要保证胜率最大,所以只须要统计当前机器人出拳的最多的那个是什么便可,然后每次都成胜最多的那个便可。
代码:
spa
#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)扫描便可
代码:
code
#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
代码:ip
#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"; }