[关闭]
@dxbdly 2023-01-28T15:38:23.000000Z 字数 4555 阅读 156

2023.1.28 模拟赛记录

2023冬


预期得分:

T1 T2 T3 Sum
100 100 50 250

实际得分:

T1 T2 T3 Sum
30 100 10 140

Summary

T1: 考场上数组开小了,挂成30分
T2: 考场AC
T3: 考场上的时候想到了大致的维护策略,却执着于将线段树二分与修改放在一起写,增加了很多代码细节,导致没写出来。

T1 human

涉及算法/想法:异或,构造
思维难度:
代码难度:

Description

上了大学之后,小W 和 小Z 一起报了一门三宝课,在实践课上遇到了一些问题。
一条染色体上有 对基因,每种基因都可以用一个数 来表示,作为标号。
现在,在其中一条染色单体上某基因发生了突变。
此时染色体上有 对相同的基因和一对不同的基因。
他们通过某种方法获得了这条染色体上的全部基因。
现在他们想知道发生突变的基因的标号是什么。

Solution

想法非常神奇的一道题目。

我们考虑用一个长度为 的容器解决问题。

我们将容器分成两部分,将 二进制分解,将为 的第 位异或上 ,将为 的第 位异或上

此时,除了要求的两个数外,其他的数的贡献一定会消除,并且,容器中必定会剩下 个数,^

并且将所有数直接异或起来就可以得到 ^,则可以得到 ,

Code

  1. //The Code Is By HJC
  2. # include <cstdio>
  3. # define max(a, b) (a>b?a:b)
  4. # define min(a, b) (a<b?a:b)
  5. // # define N 1001000
  6. using namespace std;
  7. int n;
  8. // int a[N];
  9. int f[70], ban;
  10. int main() {
  11. // freopen("human.in", "r", stdin);
  12. // freopen("human.out", "w", stdout);
  13. scanf("%d", &n);
  14. for (int i = 1, a; i <= n + n; i++) {
  15. scanf("%d", &a);
  16. ban ^= a;
  17. for (int i = 0; i < 32; i++) {
  18. if ((a >> i) & 1) {
  19. f[i] ^= a;
  20. } else {
  21. f[i + 32] ^= a;
  22. }
  23. }
  24. }
  25. int ans1 = 0, ans2 = 0;
  26. for (int i = 0; i < 64; i++) {
  27. if (f[i] && f[i] != ban) {
  28. if (ans1 == 0) {
  29. ans1 = f[i];
  30. } else if (f[i] != ans1) {
  31. ans2 = f[i];
  32. break;
  33. }
  34. }
  35. }
  36. printf("%d %d\n", min(ans1, ans2), max(ans1, ans2));
  37. }

T2 garden

涉及算法/想法:前缀和,鸽巢原理
思维难度:
代码难度:

Description

上了大学之后,小W 和 小Z 一起报了一门水课,在做作业时遇到了问题。
有一个长度为 的数列 ,为一列树木的美观值。
现在有 次询问,每次给出三个数 ,
询问对于所有的
的最小值。

Solution

先转化成前缀和

则我们希望,

长度如果超过 ,则必定有

那么最多只有长度为 的区间是有用的,这部分暴力即可。

Code

  1. //The Code Is From Dawn
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 5 * 1e4 + 5;
  14. int n, Q, T;
  15. int a[maxn], Answer;
  16. struct node {
  17. int l, r, id;
  18. };
  19. signed main() {
  20. freopen("garden.in", "r", stdin);
  21. freopen("garden.out", "w", stdout);
  22. n = read(), Q = read();
  23. for(register int i = 1; i <= n; ++i) a[i] = read();
  24. while(Q--) {
  25. int il = read(), ir = read(), mod = read();
  26. if(ir - il + 1 > mod) { printf("0\n"); continue; }
  27. Answer = 1e9 + 7;
  28. for(register int l = il; l <= ir; ++l) {
  29. int Cnt = 0;
  30. for(register int r = l; r <= ir; ++r) {
  31. Cnt = (Cnt + a[r]) % mod;
  32. Answer = min(Answer, Cnt);
  33. }
  34. }
  35. printf("%lld\n", Answer);
  36. }
  37. return 0;
  38. }

T3 psy

涉及算法/想法:线段树,线段树二分
思维难度:
代码难度:

Description

给定 个三元组 ,要求分到 个集合 , , 中,每个集合的价值是三元组中对应元素的最大值,要求三个集合价值之和最小。

Solution

考虑枚举 ,计算

容易得到一个 的做法。

发现每次重新排序太冗余,考虑将 的枚举倒过来,则每次只需要加入一个双元组

考虑他对后半段答案的影响。

我们可以将答案表示为 其中 的后缀最大值。

那么只有在 的区间中,满足 的子区间会被影响到,并且是一个区间推平的操作。

那么考虑维护一颗线段树,每次线段树上二分出子区间的左端点,将子区间做区间推平,顺便维护答案即可。

  1. //The Code Is From Dawn
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 1e5 + 5, INF = 1e9 + 7;
  14. int n, Answer;
  15. struct node {
  16. int a, b, c;
  17. }Point[maxn];
  18. int ls[maxn], tot;
  19. namespace Sigment_Tree {
  20. struct node_Tree {
  21. int Suf, minn;
  22. int lz;
  23. }Tree[maxn << 2];
  24. #define lc(i) i << 1
  25. #define rc(i) i << 1 | 1
  26. inline void Push_Up(int i) {
  27. Tree[i].Suf = min(Tree[lc(i)].Suf, Tree[rc(i)].Suf);
  28. Tree[i].minn = min(Tree[lc(i)].minn, Tree[rc(i)].minn);
  29. }
  30. inline void Build(int i, int l, int r) {
  31. Tree[i].Suf = 0;
  32. if(l == r) { Tree[i].minn = ls[l]; return ; }
  33. int mid = (l + r) >> 1;
  34. Build(lc(i), l, mid), Build(rc(i), mid + 1, r);
  35. Push_Up(i);
  36. }
  37. inline void Push_Down(int i, int l, int r) {
  38. int mid = (l + r) >> 1;
  39. if(Tree[i].lz) {
  40. Tree[lc(i)].Suf = Tree[rc(i)].Suf = Tree[i].lz;
  41. Tree[lc(i)].lz = Tree[rc(i)].lz = Tree[i].lz;
  42. Tree[lc(i)].minn = Tree[i].lz + ls[l];
  43. Tree[rc(i)].minn = Tree[i].lz + ls[mid + 1];
  44. Tree[i].lz = 0;
  45. }
  46. }
  47. inline void Update(int i, int l, int r, int ql, int qr, int num) {
  48. if(l >= ql && r <= qr) {
  49. Tree[i].minn = num + ls[l];
  50. Tree[i].lz = Tree[i].Suf = num;
  51. return ;
  52. }
  53. Push_Down(i, l, r);
  54. int mid = (l + r) >> 1;
  55. if(ql <= mid) Update(lc(i), l, mid, ql, qr, num);
  56. if(qr > mid) Update(rc(i), mid + 1, r, ql, qr, num);
  57. Push_Up(i);
  58. }
  59. inline int Find(int i, int l, int r, int num) {
  60. Push_Down(i, l, r);
  61. if(l == r) return l;
  62. int mid = (l + r) >> 1;
  63. if(Tree[lc(i)].Suf <= num) return Find(lc(i), l, mid, num);
  64. else return Find(rc(i), mid + 1, r, num);
  65. }
  66. }
  67. using namespace Sigment_Tree;
  68. signed main() {
  69. freopen("psy.in", "r", stdin);
  70. freopen("psy.out", "w", stdout);
  71. n = read();
  72. for(register int i = 1; i <= n; ++i) {
  73. Point[i].a = read();
  74. ls[++tot] = Point[i].b = read();
  75. Point[i].c = read();
  76. }
  77. sort(ls + 1, ls + tot + 1); tot = unique(ls + 1, ls + tot + 1) - ls - 1;
  78. for(register int i = 1; i <= n; ++i) Point[i].b = lower_bound(ls + 1, ls + tot + 1, Point[i].b) - ls;
  79. sort(Point + 1, Point + n + 1, [&](node x, node y){ return x.a < y.a; });
  80. Answer = Point[n].a, Build(1, 0, tot);
  81. for(register int i = n - 1; i >= 0; --i) {
  82. int pos = Find(1, 0, tot, Point[i + 1].c);
  83. Update(1, 0, tot, pos, Point[i + 1].b - 1, Point[i + 1].c);
  84. Answer = min(Answer, Point[i].a + Tree[1].minn);
  85. }
  86. printf("%lld\n", Answer);
  87. return 0;
  88. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注