• [补题记录] Atcoder Beginner Contest 308(C~E)


    URL:https://atcoder.jp/contests/abc308

    目录

    C

    Problem/题意

    Thought/思路

    Code/代码

    D

    Problem/题意

    Thought/思路

    Code/代码

    E

    Problem/题意

    Thought/思路

    Code/代码


    C

    Problem/题意

    给出n个(a,b)数对,定义成功率为 a / (a + b),按照成功率降序排序,输出数对编号。

    Thought/思路

    坑:当成功率相同时,要求编号小的在前。

    Code/代码

    1. #include "bits/stdc++.h"
    2. #define int long long
    3. int n;
    4. struct node {
    5. int id;
    6. int a, b;
    7. bool operator < (const node &t) const {
    8. if (a * (t.a + t.b) == t.a * (a + b)) return id < t.id; // 按原顺序比较
    9. else return a * (t.a + t.b) > t.a * (a + b);
    10. }
    11. };
    12. signed main() {
    13. std::cin >> n;
    14. std::vector rate(n + 1);
    15. for (int i = 1; i <= n; ++ i) {
    16. std::cin >> rate[i].a >> rate[i].b;
    17. rate[i].id = i;
    18. }
    19. std::sort(rate.begin() + 1, rate.end());
    20. for (int i = 1; i <= n; ++ i) {
    21. std::cout << rate[i].id << " ";
    22. }
    23. }

    D

    Problem/题意

    给一个n * m的矩阵,由小写字母组成,问是否能从(1,1)走到(n,m)。行走规则是:按照“s、n、u、k、e”循环的顺序来走,也就是一开始从s出发,下一步只能走到n;当走到e,下一步只能走到s。

    Thought/思路

    简单bfs

    能走到的地方标记为1,其实就是vis

    Code/代码

    1. #include "bits/stdc++.h"
    2. int n, m, vis[507][507];
    3. char mp[507][507];
    4. const char path[6] = {'s', 'n', 'u', 'k', 'e'};
    5. const int dx[5] = {0, 1, 0, -1, 0};
    6. bool check(int x, int y, char target) {
    7. if (x < 1 or x > n or y < 1 or y > m or vis[x][y] or target != mp[x][y])
    8. return false;
    9. else
    10. return true;
    11. }
    12. bool bfs() {
    13. std::queue int, int>> q;
    14. q.push({1, 1});
    15. if (mp[1][1] != 's') return false;
    16. while (!q.empty()) {
    17. auto top = q.front(); q.pop();
    18. int x = top.first, y = top.second;
    19. if (vis[x][y]) continue;
    20. else vis[x][y] = 1;
    21. char next = '#';
    22. for (int i = 0; i < 5; ++ i) {
    23. if (path[i] == mp[x][y]) {
    24. next = path[i + 1 == 5 ? 0 : i + 1];
    25. break;
    26. }
    27. }
    28. //std::cout << "next = " << next << "\n";
    29. for (int i = 0; i <= 3; ++ i) {
    30. int nx = x + dx[i], ny = y + dx[i + 1];
    31. if (check(nx, ny, next)) {
    32. q.push({nx, ny});
    33. }
    34. }
    35. }
    36. for (int i = 1; i <= n; ++ i) {
    37. for (int j = 1; j <= m; ++ j) {
    38. // std::cout << vis[i][j] << " \n"[j == m];
    39. }
    40. }
    41. if (vis[n][m] == 1) return true;
    42. else return false;
    43. }
    44. signed main(){
    45. std::cin >> n >> m;
    46. for (int i = 1; i <= n; ++ i) {
    47. for (int j = 1; j <= m; ++ j) {
    48. std::cin >> mp[i][j];
    49. }
    50. }
    51. if(bfs()) {
    52. std::cout << "Yes";
    53. } else {
    54. std::cout << "No";
    55. }
    56. }

    E

    Problem/题意

    给一个数组 a,由 0、1、2 组成;给一个字符串 s,由 M、E、X 组成。

    在 s 中选择 s[i] s[j] s[k] = M E X 的子序列串,求 mex(ai, aj, ak) 的和。

    Thought/思路

    因为 MEX 的顺序固定,因此考虑以 E 作为出发点,假设数组 a 中仅有 1,那么每个 E 的位置能贡献的答案就是 ans += M_pre * X_rep * Mex(1, 1, 1),即 前缀M的数量 × 后缀X的数量 × 1。

    但是该题数组 a 中包含 0、1、2,那么只需要对 M 和 X 都多考虑 0 和 2 的情况即可,也就是多维护两个前缀 {M, 0}、{M, 2} 和两个后缀 {X, 0}、{X, 2} 。

    Code/代码

    1. #include "bits/stdc++.h"
    2. #define int long long
    3. int n, a[200005];
    4. std::string s;
    5. std::mapint, int>, int> pre[200005];
    6. // pre[2][{'M', 0}]:1~2之间,M 对应 a 为 0 的情况有多少种
    7. std::mapint, int>, int> rep[200005];
    8. int Mex(int a, int b, int c) {
    9. std::bitset <4> st;
    10. st[a] = st[b] = st[c] = 1;
    11. for (int i = 0; i <= 3; ++ i) {
    12. if (st[i] == 0)
    13. return i;
    14. }
    15. return 0;
    16. }
    17. signed main() {
    18. std::cin >> n;
    19. for (int i = 1; i <= n; ++ i) std::cin >> a[i];
    20. std::cin >> s;
    21. s = "#" + s;
    22. for (int i = 1; i <= n; ++ i) {
    23. for (auto &c : {'M', 'E', 'X'})
    24. for (int j = 0; j <= 2; ++ j)
    25. pre[i][{c, j}] = pre[i - 1][{c, j}] + (c == s[i] and j == a[i]);
    26. }
    27. for (int i = n; i >= 1; -- i) {
    28. for (auto &c : {'M', 'E', 'X'})
    29. for (int j = 0; j <= 2; ++ j)
    30. rep[i][{c, j}] = rep[i + 1][{c, j}] + (c == s[i] and j == a[i]);
    31. }
    32. int ans = 0;
    33. for (int i = 2; i <= n - 1; ++ i) {
    34. if (s[i] == 'E') {
    35. for (int j = 0; j <= 2; ++ j) { // M
    36. for (int k = 0; k <= 2; ++ k) { // X
    37. int mex = Mex(j, a[i], k);
    38. ans += mex * (pre[i - 1][{'M', j}] * rep[i + 1][{'X', k}]);
    39. }
    40. }
    41. }
    42. }
    43. std::cout << ans;
    44. }

  • 相关阅读:
    云原生实战课大纲
    云原生周刊:Gateway API v1.1 发布 | 2024.6.3
    LeetCode198:打家劫舍
    【高效开发工具系列】Fork版本管理
    java父类子类调用时序
    如何利用Redis进行事务处理呢?
    适合初学者的云服务器——观星云
    RPC通信原理以及项目的技术选型
    Paper Reading:《Consistent-Teacher: 减少半监督目标检测中不一致的伪目标》
    环信uni-app-demo 升级改造计划——单人&多人音视频通话(三)
  • 原文地址:https://blog.csdn.net/joyride_run/article/details/131508443