当前位置:   article > 正文

AtCoder Beginner Contest 330 题解_(atcoder beginner contest 330) 题解

(atcoder beginner contest 330) 题解

目录

A. Counting Passes

B. Minimize Abs 1

C. Minimize Abs 2

D. Counting Ls

E. Mex and Update

F. Minimize Bounding Square


A. Counting Passes

思路:直接遍历一遍,记录有多少个人的得分大于等于L。

代码:

  1. void solve()
  2. {
  3. cin >> n >> m;
  4. int sum = 0;
  5. for(int i = 1; i <= n; i ++)
  6. {
  7. int t;
  8. cin >> t;
  9. if(t >= m) sum ++;
  10. }
  11. cout << sum << endl;
  12. }

B. Minimize Abs 1

思路:如果输入的数是比l小的答案为l,如果输入的数在l到r的范围内,则答案为数本身,如果输入的数大于r的答案为r。

代码:

  1. void solve()
  2. {
  3. int l, r;
  4. cin >> n >> l >> r;
  5. for(int i = 1; i <= n; i ++)
  6. {
  7. int t;
  8. cin >> t;
  9. if(t <= l)
  10. {
  11. cout << l << ' ';
  12. }
  13. else if(l < t && t < r)
  14. {
  15. cout << t << ' ';
  16. }
  17. else cout << r << ' ';
  18. }
  19. }

C. Minimize Abs 2

思路:直接暴力枚举x和y就好。枚举到x的平方大于n的时候break。枚举的时候注意y的取值,可以是sqrt(abs(n - x * x)) + 1, 或者是 sqrt(abs(n - x * x))。int sqrt()的时候 :因为返回类型是整数,结果只保留整数部分,小数部分将被舍去。

代码:

  1. void solve()
  2. {
  3. int l, r;
  4. cin >> n;
  5. int sum = n;
  6. for(int i = 1; i * i <= 2e12; i ++)
  7. {
  8. int t = i * i;
  9. if(t > n) break;
  10. int p = abs(n - t);
  11. int q = sqrt(p);
  12. int su = abs(t + q * q - n);
  13. q ++;
  14. sum = min(sum, su);
  15. su = abs(t + q * q - n);
  16. sum = min(sum, su);
  17. }
  18. cout << sum << endl;
  19. }

D. Counting Ls

思路:题目要求

  • 正好有两个单元格在同一行。
  • 正好有两个单元格位于同一列
  • 所有三个单元格中都写有一个 o。

 我们设三个点的坐标是(x1, y1), (x2, y2), (x3, y3) 其中 x2 = x1 ,y2 = y3。所以我们只需要找出第二个点 (x2, y2),对答案的贡献就是(row[i] - 1) * (col[j] - 1) 其中row[i] 表示 第i行有多少个元素是o,col[j] 表示第j行有多少个元素是o。

代码:

  1. int n, m, k;
  2. int row[2020], col[2020];
  3. char c[2020][2020];
  4. void solve()
  5. {
  6. cin >> n;
  7. for(int i = 1; i <= n; i ++)
  8. {
  9. for(int j = 1; j <= n; j ++)
  10. {
  11. cin >> c[i][j];
  12. if(c[i][j] == 'o') row[i] ++, col[j] ++;
  13. }
  14. }
  15. int sum = 0;
  16. for(int i = 1; i <= n; i ++)
  17. {
  18. for(int j = 1; j <= n; j ++)
  19. {
  20. if(c[i][j] == 'o')
  21. {
  22. sum += ((row[i] - 1) * (col[j] - 1));
  23. }
  24. }
  25. }
  26. cout << sum << endl;
  27. }

E. Mex and Update

思路:运用set和map,map存每个数出现的次数,set存每个数是否出现过,当一个数的出现次数变成0后,set将其加入,反之当一个数出现次数大于0的时候,set将其删除。首先,我们先把0到n都存到set里面去(初始时0 - n在数组中都没出现过).。 然后按照题目要求模拟即可,每次操作后的答案就是set中存的第一个元素。set中存的元素是排好序的。

代码:

  1. void solve()
  2. {
  3. cin >> n;
  4. cin >> m;
  5. map<int, int> mp;
  6. set<int> s;
  7. for(int i = 0; i <= n; i ++)
  8. {
  9. s.insert(i);
  10. }
  11. for(int i = 1; i <= n; i ++)
  12. {
  13. cin >> a[i];
  14. mp[a[i]] ++;
  15. s.erase(a[i]);
  16. }
  17. for(int i = 1; i <= m; i ++)
  18. {
  19. int op, l, r;
  20. cin >> l >> r;
  21. mp[a[l]] --;
  22. if(mp[a[l]] == 0) s.insert(a[l]);
  23. a[l] = r;
  24. mp[a[l]] ++;
  25. s.erase(r);
  26. cout << *s.begin() << endl;
  27. }
  28. }

F. Minimize Bounding Square

思路:二分答案,利用前缀和优化。

x和y这两个元素可以分开看,相当于一维里面的两个直线。

如果正方形边长越大,我们需要的移动次数越少,相反,正方形边长越小,需要移动的次数越多。这里有一个单调性,因此我们可以二分最终的正方形边长。边长固定了,考虑到最优情况下,覆盖的线段必定有一端点上的点是从来没移动过的,因此我们可以枚举这个作为边界的点。然后计算需要移动的次数。

我们先将坐标从小到大排序,然后预处理出一个前缀坐标和。注意需要分别枚举作为左端点的点和作为右端点的点。

两个维度分别取所需移动次数的最小值,其和不超过k则边长可行。

(代码中我把k的变量名定义为m了。抱一丝qwq)

代码:

  1. int x[N], y[N], sumx[N], sumy[N];
  2. int fun(int a[], int s[], int mid)
  3. {
  4. int ans = 1e18;
  5. for(int i = 1; i <= n; i ++)
  6. {
  7. int t = i * a[i] - s[i];
  8. int R = a[i] + mid;
  9. int l = 1, r = n;
  10. while(l < r)
  11. {
  12. int midd = l + r >> 1;
  13. if(a[midd] > R) r = midd;
  14. else l = midd + 1;
  15. }
  16. if(a[l] > R)
  17. {
  18. t += s[n] - s[l - 1] - (n - l + 1) * R;
  19. }
  20. ans = min(ans, t);
  21. }
  22. for(int i = n; i >= 1; i --)
  23. {
  24. int t = s[n] - s[i - 1] - (n - i + 1) * a[i];
  25. int L = a[i] - mid;
  26. int l = 1, r = n;
  27. while(l < r)
  28. {
  29. int midd = l + r + 1 >> 1;
  30. if(a[midd] < L) l = midd;
  31. else r = midd - 1;
  32. }
  33. if(a[l] < L)
  34. {
  35. t += l * L - s[l];
  36. }
  37. ans = min(ans, t);
  38. }
  39. return ans;
  40. }
  41. bool check(int mid)
  42. {
  43. int t = fun(x, sumx, mid) + fun(y, sumy, mid);
  44. return t <= m;
  45. }
  46. void solve()
  47. {
  48. cin >> n >> m;
  49. for(int i = 1; i <= n; i ++)
  50. {
  51. cin >> x[i] >> y[i];
  52. }
  53. sort(x + 1, x + 1 + n);
  54. sort(y + 1, y + 1 + n);
  55. for(int i = 1; i <= n; i ++)
  56. {
  57. sumx[i] = x[i] + sumx[i - 1];
  58. sumy[i] = y[i] + sumy[i - 1];
  59. }
  60. int l = 0, r = 1e9;
  61. while(l < r)
  62. {
  63. int mid = l + r >> 1;
  64. if(check(mid)) r = mid;
  65. else l = mid + 1;
  66. }
  67. cout << l << endl;
  68. }

链接:TOYOTA SYSTEMS Programming Contest 2023(AtCoder Beginner Contest 330) - AtCoder

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/877202
推荐阅读
  

闽ICP备14008679号