[关闭]
@dxbdly 2022-07-16T03:18:59.000000Z 字数 6325 阅读 183

7.13暑期模拟赛

2022暑


期望得分:

T1 T2 T3 Sum
100 50 80 230

实际得分:

T1 T2 T3 Sum
95 50 0 145

T1 tsm

首先考虑没有修改的情况。

最后的游戏,是一个典型的 游戏,那么就只要考虑如何求出

图上路径最大边权最小问题,参考货车运输,考虑最小生成树 +

稍微给个证明:考虑反证,如果答案不落在最小生成树上,那么可以将这条边替换进最小生成树中。

再将修改考虑进去。

实际上就是在树上多填了一条边,考虑找出环,若新增的边更小,删去最大的边,并重新初始化倍增数组。

每部分的思路比较经典,是道缝合题,比较考验代码能力

  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 = 5000, maxm = 1e5 + 5;
  14. int n, m;
  15. struct Map {
  16. struct node {
  17. int u, v, nex;
  18. int w, flag;
  19. }edge[maxm << 3];
  20. map < pair<int, int>, int > mapp;
  21. int head[maxm << 3], len;
  22. inline void make_map(int u, int v, int w, int flag) {
  23. len++;
  24. edge[len].nex = head[u];
  25. edge[len].u = u;
  26. edge[len].v = v;
  27. edge[len].w = w;
  28. edge[len].flag = flag;
  29. head[u] = len;
  30. }
  31. }Tree, Mapp;
  32. namespace MST {
  33. int Father[maxm];
  34. inline bool cmp(Map::node x, Map::node y) {
  35. return x.w < y.w;
  36. }
  37. inline int Find(int x) {
  38. if(Father[x] != x) return Father[x] = Find(Father[x]);
  39. return Father[x];
  40. }
  41. inline void Unnion(int x, int y) {
  42. int f1 = Find(x), f2 = Find(y);
  43. if(f1 != f2) Father[f2] = f1;
  44. }
  45. inline void Kruskal() {
  46. int tot = 0;
  47. for(register int i = 1; i <= m; ++i) {
  48. int u = Mapp.edge[i].u, v = Mapp.edge[i].v, w = Mapp.edge[i].w;
  49. if(Find(u) != Find(v)) {
  50. Unnion(u, v), tot++, Tree.make_map(u, v, w, 1), Tree.mapp[make_pair(u, v)] = Tree.len, Tree.make_map(v, u, w, 1), Tree.mapp[make_pair(v, u)] = Tree.len;
  51. if(tot == n - 1) break;
  52. }
  53. }
  54. }
  55. inline void Work() {
  56. for(register int i = 1; i <= n; ++i) Father[i] = i;
  57. sort(Mapp.edge + 1, Mapp.edge + m + 1, cmp);
  58. Kruskal();
  59. }
  60. }
  61. namespace LCA {
  62. int f[maxm][25], maxx[maxm][25], dep[maxm];
  63. int Lca, Maxx;
  64. inline void Deal_First(int x, int fa) {
  65. dep[x] = dep[fa] + 1;
  66. for(register int i = 1; i <= 20; ++i) {
  67. f[x][i] = f[f[x][i - 1]][i - 1];
  68. maxx[x][i] = max(maxx[x][i - 1], maxx[f[x][i - 1]][i - 1]);
  69. }
  70. for(register int i = Tree.head[x]; i; i = Tree.edge[i].nex) {
  71. int y = Tree.edge[i].v, z = Tree.edge[i].w, flag = Tree.edge[i].flag;
  72. if(y == fa || !flag) continue;
  73. f[y][0] = x, maxx[y][0] = z;
  74. Deal_First(y, x);
  75. }
  76. }
  77. inline void Get_Lca(int x, int y) {
  78. if(dep[x] < dep[y]) swap(x, y);
  79. Lca = Maxx = 0;
  80. for(register int i = 20; i >= 0; --i)
  81. if(dep[f[x][i]] >= dep[y]) Maxx = max(Maxx, maxx[x][i]), x = f[x][i];
  82. if(x == y) { Lca = x; return ;}
  83. for(register int i = 20; i >= 0; --i)
  84. if(f[x][i] != f[y][i]) Maxx = max(Maxx, max(maxx[x][i], maxx[y][i])), x = f[x][i], y = f[y][i];
  85. Lca = f[x][0], Maxx = max(Maxx, max(maxx[x][0], maxx[y][0]));
  86. }
  87. inline int Erase(int x, int y, int z) {
  88. Get_Lca(x, y);
  89. if(Maxx < z) return 0;
  90. int now = 0; Maxx = 0;
  91. while(x != Lca) {
  92. if(maxx[x][0] > Maxx) Maxx = maxx[x][0], now = x;
  93. x = f[x][0];
  94. }
  95. while(y != Lca) {
  96. if(maxx[y][0] > Maxx) Maxx = maxx[y][0], now = y;
  97. y = f[y][0];
  98. }
  99. return now;
  100. }
  101. inline void Work() {
  102. Deal_First(1, 0);
  103. }
  104. }
  105. namespace Solve {
  106. using LCA::Maxx; using LCA::Get_Lca; using LCA::Deal_First; using LCA::Erase; using LCA::f;
  107. inline bool Check(int x, int y) { return (x ^ y) != 0; }
  108. inline void Work() {
  109. int Q = read();
  110. while(Q--) {
  111. char s[15];
  112. scanf("%s", s);
  113. if(s[0] == 'a') {
  114. int u = read(), v = read(), q = read(), x = Erase(u, v, q);
  115. if(!x) continue;
  116. int y = f[x][0];
  117. Tree.edge[Tree.mapp[make_pair(x, y)]].flag = 0, Tree.edge[Tree.mapp[make_pair(y, x)]].flag = 0;
  118. Tree.make_map(u, v, q, 1), Tree.mapp[make_pair(u, v)] = Tree.len, Tree.make_map(v, u, q, 1), Tree.mapp[make_pair(v, u)] = Tree.len;
  119. Deal_First(1, 0);
  120. }
  121. else {
  122. int m1 = read(), m2 = read(), b1 = read(), b2 = read();
  123. Get_Lca(m1, m2); int M = Maxx;
  124. Get_Lca(b1, b2); int B = Maxx;
  125. if(Check(M, B)) printf("madoka\n");
  126. else printf("Baozika\n");
  127. }
  128. }
  129. }
  130. }
  131. signed main() {
  132. // freopen("tsm.in", "r", stdin);
  133. // freopen("tsm.out", "w", stdout);
  134. n = read(), m = read();
  135. for(register int i = 1; i <= m; ++i) {
  136. int u = read(), v = read(), w = read();
  137. Mapp.make_map(u, v, w, 1);
  138. }
  139. MST::Work(), LCA::Work(), Solve::Work();
  140. return 0;
  141. }

T2 ihp

经典结论

所以此题的 就是

是个积性函数,所以可以直接线性筛

至于剩下两个提答点,直接跑分解。

  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 = 3e7 + 5;
  14. int n;
  15. int a[maxn], Phi[maxn], Vst[maxn], Prime[maxn], maxx, Ans, tot;
  16. inline void Get_Phi() {
  17. Phi[1] = 1;
  18. for(register int i = 2; i <= maxx; ++i) {
  19. if(!Vst[i]) Prime[++tot] = i, Phi[i] = i - 1;
  20. for(register int j = 1; j <= tot && i * Prime[j] <= maxx; ++j) {
  21. Vst[i * Prime[j]] = 1;
  22. if(i % Prime[j] == 0) { Phi[i * Prime[j]] = Phi[i] * Prime[j]; break; }
  23. else Phi[i * Prime[j]] = Phi[i] * (Prime[j] - 1);
  24. }
  25. }
  26. }
  27. signed main() {
  28. // freopen("ihp.in", "r", stdin);
  29. // freopen("ihp.out", "w", stdout);
  30. n = read();
  31. if(n == 5) { printf("21517525747423580"); return 0; }
  32. if(n == 3) { printf("525162079891401242"); return 0; }
  33. for(register int i = 1; i <= n; ++i) a[i] = read(), maxx = max(maxx, a[i]);
  34. Get_Phi();
  35. for(register int i = 1; i <= n; ++i) Ans += Phi[a[i]];
  36. printf("%lld\n", Ans);
  37. return 0;
  38. }

T3 qmras

Solve1:SAM

最近学了下 ,能解决大部分子串类字符串问题

此题就是个 板子,建出 后求出每个点 的集合大小,乘上每个点长度小于 的本质不同子串数量

后者的计算方式:

  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 = 1e6 + 5, mod = 998244353;
  14. int n, k;
  15. char s[maxn];
  16. struct Map {
  17. int v, nex;
  18. }edge[maxn << 1];
  19. struct node {
  20. int link, len;
  21. int Ch[26];
  22. }SAM[maxn];
  23. int head[maxn], len;
  24. int Siz[maxn], tot, Last, Answer;
  25. inline void make_map(int u, int v) {
  26. len++;
  27. edge[len].nex = head[u];
  28. edge[len].v = v;
  29. head[u] = len;
  30. }
  31. inline void Init() { SAM[1].len = 0, Last = 1, SAM[1].link = 0, tot++; }
  32. inline void Insert(int c) {
  33. int q = ++tot, p = Last; SAM[q].len = SAM[p].len + 1, Last = q, Siz[q] = 1;
  34. while(p && !SAM[p].Ch[c]) SAM[p].Ch[c] = q, p = SAM[p].link;
  35. if(!p) SAM[q].link = 1;
  36. else {
  37. int x = SAM[p].Ch[c];
  38. if(SAM[p].len + 1 == SAM[x].len) SAM[q].link = x;
  39. else {
  40. int y = ++tot; SAM[y].len = SAM[p].len + 1;
  41. SAM[y].link = SAM[x].link, SAM[q].link = SAM[x].link = y;
  42. memcpy(SAM[y].Ch, SAM[x].Ch, sizeof(SAM[x].Ch));
  43. while(p && SAM[p].Ch[c] == x) SAM[p].Ch[c] = y, p = SAM[p].link;
  44. }
  45. }
  46. }
  47. inline void Search(int x) {
  48. for(register int i = head[x]; i; i = edge[i].nex) {
  49. int y = edge[i].v;
  50. Search(y);
  51. Siz[x] += Siz[y];
  52. }
  53. if(Siz[x] > 1) Answer = (Answer + (Siz[x] * (Siz[x] - 1) / 2) % mod * max(0ll, min(k, SAM[x].len) - SAM[SAM[x].link].len) % mod % mod) % mod;
  54. }
  55. signed main() {
  56. // freopen("qmras.in", "r", stdin);
  57. // freopen("qmras.out", "w", stdout);
  58. n = read(), k = read();
  59. scanf("%s", s), Init();
  60. for(register int i = 0; i < n; ++i) Insert(s[i] - 'a');
  61. for(register int i = 2; i <= tot; ++i) make_map(SAM[i].link, i);
  62. Search(1);
  63. printf("%lld\n", Answer);
  64. return 0;
  65. }

Solve2:Hash

由于保证数据随机,考虑长度很长的相同串不可能出现,所以可以自己设置 的取值,然后直接前缀 即可。

最后调调 就好了,大概20的样子就能过。

Solve3:Sa + RMQ

大概思路是利用 数组,再用 维护一下区间最大(其实我也不是很清楚bushi)。

还是推荐学习 !!!

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注