补题链接:Here

1525A. Potion-making (思维

【题意描述】

作为一个魔法师,现在我想配置一杯药物浓度为 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图1 的药水,

每次操作能进行添加:

  • 一升水
  • 一升药物精华

作为魔法师并不在意最后配出来药水升数,请问最少进行多少次操作能得到结果

【思路分析】

先不管 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图2 是多少但最多 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图3 次操作一定能得到想要的结果,

但某些情况下是不需要执行那么多次结果的,比如 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图4 ,此时只要进行 4 次

这样的话很容易想到求一下 100 / 公约数即可

【AC 代码】

  1. void solve() {
  2. int n;
  3. cin >> n;
  4. cout << 100 / __gcd(100, n) << "\n";
  5. }

1525B. Permutation Sort (思维

【题意描述】

给定一个可能无序的数组a(1~n),现在允许执行操作:对数组按任意情况重排序,但最多 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图5 区间内重排

请问在给定数组的情况下最少执行多少次?

【思路分析】

  • 情况1 :本身就有序了,输出 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图6
  • 情况2:Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图7 则排一次补集即可
  • 特殊3:Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图8Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图9 此时先排 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图10 然后排 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图11,再排 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图12。3次一定能得到升序(当然3次排序还有其他写法)
  • 情况4:不是以上情况的情况下一定 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图13 次排完

【AC 代码】

  1. int main() {
  2. ios::sync_with_stdio(false), cin.tie(nullptr);
  3. int _;
  4. for (cin >> _; _--;) {
  5. int n;
  6. cin >> n;
  7. int a[n + 1];
  8. int cnt = 0;
  9. for (int i = 1; i <= n; ++i) {
  10. cin >> a[i];
  11. if (a[i] != i)cnt++;
  12. }
  13. if (cnt == 0) cout << "0\n";
  14. else if (a[1] == 1 || a[n] == n)cout << "1\n";
  15. else {
  16. if (a[1] == n and a[n] == 1)cout << "3\n";
  17. else cout << "2\n";
  18. }
  19. }
  20. return 0;
  21. }

1525C. Robot Collisions

比赛的时候看出来是一道很复杂的模拟题就没去想

这里贴一下大佬的代码作为学习,开启C++17以便使用 tuple 元组

【AC 代码】

  1. int n, m;
  2. void solve() {
  3. cin >> n >> m;
  4. vector<pair<int, int>>a(n);
  5. for (int i = 0; i < n; ++i)cin >> a[i].first;
  6. for (int i = 0; i < n; ++i) {
  7. char c; cin >> c;
  8. a[i].second = (c == 'R' ? 1 : 0);
  9. }
  10. vector<tuple<int, int, int>>v[2];
  11. for (int i = 0; i < n; ++i) {
  12. int val = (a[i].first & 1);
  13. v[val].emplace_back(a[i].first, a[i].second, i);
  14. }
  15. vector<int>ans(n, -1);
  16. auto calc = [&](vector<tuple<int, int, int>>&v)->void {
  17. sort(v.begin(), v.end());
  18. stack<pair<int, int>>st;
  19. for (auto&[x, d, ind] : v) {
  20. if (d == 0) {
  21. if (st.empty())st.push(make_pair(-x, ind));
  22. else {
  23. ans[st.top().second] = ans[ind] = (x - st.top().first) / 2;
  24. st.pop();
  25. }
  26. } else st.push(make_pair(x, ind));
  27. }
  28. while (st.size() > 1) {
  29. pair<int, int> p = st.top();
  30. st.pop();
  31. p.first = m + (m - p.first);
  32. ans[p.second] = ans[st.top().second] = (p.first - st.top().first) / 2;
  33. st.pop();
  34. }
  35. };
  36. calc(v[0]), calc(v[1]);
  37. for (int &x : ans)cout << x << " ";
  38. cout << "\n";
  39. }

1525D. Armchairs

【题意描述】

现有 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图14 个座位,有最多不超过 Educational Codeforces Round 109 (Rated for Div. 2) 个人补题记录(A~D,AB思维,C模拟构造,D题DP) - 图15 的人已经就座了,但由于某种情况每个人都不能坐在原来的位置,需要移动到最近的空位置(并且别人原本的位置是不能坐的,别人在移动时剩余的人不能动),请输出最少的移动距离和 (每个人的移动距离为:new seat- old seat)

【思路分析】

这道题在比赛时用贪心没写出来,然后推测需要DP优化,但没处理好

赛后看了一下高Rank写法发现这道题应该先分开来保存空位置和有人的位置,利用记忆化去枚举有人的位置到所有的空位置的最小代价

【AC 代码】

  1. const int N = 5010;
  2. int c[N], b[N], f[N];
  3. void solve() {
  4. int n;
  5. cin >> n;
  6. int cb = 0, cc = 0;
  7. // 分别记录下标
  8. for (register int i = 1, te; i <= n; ++i) {
  9. cin >> te;
  10. (te ? b[++cb] : c[++cc]) = i;
  11. }
  12. // 注意这里不需要初始化全部位置
  13. memset(f + 1, 0x3f, sizeof(int) * cb);
  14. for (int i = 1; i <= cc; i++) {
  15. for (int j = min(cb, i); j >= 1; j--) {
  16. f[j] = min(f[j], f[j - 1] + abs(b[j] - c[i]));
  17. }
  18. }
  19. cout << f[cb] << "\n";
  20. }

顺序记录一下没考虑全面时写的贪心解法 WA8

  1. using ll = long long;
  2. const int N = 5010;
  3. int a[N], vis[N];
  4. int n;
  5. int rdfs(int x) {
  6. while ((a[x] == 1 or a[x] == -1) and x >= 1)x--;
  7. if (x <= 0)x = -1;
  8. return x;
  9. }
  10. int ldfs(int x) {
  11. while ((a[x] == 1 or a[x] == -1) and x <= n)x++;
  12. if (x > n)x = -1;
  13. return x;
  14. }
  15. void solve() {
  16. cin >> n;
  17. int cnt = 0;
  18. for (int i = 1; i <= n; ++i)cin >> a[i], cnt += a[i];
  19. if (cnt == 0) {cout << "0\n"; return ;}
  20. int ans = 0;
  21. for (int i = 1; i <= n; ++i) {
  22. if (a[i] == 1) {
  23. int r = rdfs(i), l = ldfs(i);
  24. cout << i << " " << l << " " << r << "\n";
  25. if (r == -1 and l != -1) ans += l - i, a[l] = -1;
  26. else if (l == -1 and r != -1)ans += i - r, a[r] = -1;
  27. else if (l != -1 and r != -1) {
  28. if (l - i <= i - r) a[l] = -1, ans += l - i;
  29. else a[r] = -1, ans += i - r;
  30. }
  31. }
  32. }
  33. cout << ans << "\n";
  34. }