[关闭]
@Dmaxiya 2018-08-17T10:13:50.000000Z 字数 7405 阅读 975

Codeforces Round #457 (Div. 2)

Codeforces


Contests 链接:Codeforces Round #457 (Div. 2)
过题数:2
排名:447/6352

A. Jamie and Alarm Snooze

题意

想睡懒觉,但是他必须要在 时刻起床,于是他需要提前定一个含有 数字 的时刻作为第一次闹钟响起的时刻,已经知道他每隔 分钟就会按下闹钟的“贪睡”按钮,问他第一次闹钟的时间是多少。

数据范围

题解

按照给定时刻每次往前跑 分钟,判断该时间是否含有数字

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. int x, h, m;
  21. int ans;
  22. void cut_x(int &h, int &m, int x) {
  23. m -= x;
  24. if(m < 0) {
  25. m += 60;
  26. h -= 1;
  27. if(h < 0) {
  28. h += 24;
  29. }
  30. }
  31. }
  32. int main() {
  33. #ifdef LOCAL
  34. freopen("test.txt", "r", stdin);
  35. // freopen("out.txt", "w", stdout);
  36. #endif // LOCAL
  37. ios::sync_with_stdio(false);
  38. while(scanf("%d%d%d", &x, &h, &m) != EOF) {
  39. int ans = 0;
  40. while(h % 10 != 7 && m % 10 != 7) {
  41. cut_x(h, m, x);
  42. ++ans;
  43. }
  44. printf("%d\n", ans);
  45. }
  46. return 0;
  47. }

B. Jamie and Binary Sequence

题意

分成 相加,若不能拆分,则输出 ,否则找到 ,且字典序最大的满足条件的序列,题目保证答案的范围在 之间。

数据范围

题解

先判断是否可以用 个数字来表示 ,若可行,用大顶堆将最大值弹出,拆成两个小的进入堆,直到堆的大小为 ,以此确定 ,然后根据这个值贪心构造数列。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 63;
  21. const int maxm = 100000 + 100;
  22. int cnt, k;
  23. LL n;
  24. LL two[maxn];
  25. int ans[maxm];
  26. priority_queue<int> que;
  27. void Pull(int Max, LL n) {
  28. cnt = 0;
  29. while(n != 0) {
  30. LL *it = upper_bound(two, two + maxn, n);
  31. --it;
  32. n -= *it;
  33. if(Max < it - two) {
  34. for(int i = 0; i < two[it - two - Max]; ++i) {
  35. ans[cnt++] = Max;
  36. }
  37. } else {
  38. ans[cnt++] = it - two;
  39. }
  40. }
  41. while(cnt != k) {
  42. ans[cnt - 1] = ans[cnt - 1] - 1;
  43. ans[cnt] = ans[cnt - 1];
  44. ++cnt;
  45. }
  46. }
  47. int main() {
  48. #ifdef LOCAL
  49. freopen("test.txt", "r", stdin);
  50. // freopen("out.txt", "w", stdout);
  51. #endif // LOCAL
  52. ios::sync_with_stdio(false);
  53. two[0] = 1;
  54. for(int i = 1; i < maxn; ++i) {
  55. two[i] = two[i - 1] << 1;
  56. }
  57. while(scanf("%I64d%d", &n, &k) != EOF) {
  58. while(!que.empty()) {
  59. que.pop();
  60. }
  61. LL nn = n;
  62. while(n != 0) {
  63. LL *it = upper_bound(two, two + maxn, n);
  64. --it;
  65. que.push(it - two);
  66. n -= *it;
  67. if((int)que.size() == k) {
  68. break;
  69. }
  70. }
  71. if(n != 0) {
  72. printf("No\n");
  73. continue;
  74. }
  75. printf("Yes\n");
  76. while((int)que.size() < k) {
  77. int tmp = que.top();
  78. que.pop();
  79. --tmp;
  80. que.push(tmp);
  81. que.push(tmp);
  82. }
  83. int Max = que.top();
  84. Pull(Max, nn);
  85. for(int i = 0; i < cnt; ++i) {
  86. if(i != 0) {
  87. printf(" ");
  88. }
  89. printf("%d", ans[i]);
  90. }
  91. printf("\n");
  92. }
  93. return 0;
  94. }

C. Jamie and Interesting Graph

题意

如果一张带权无向图满足以下条件,它就是一张有趣的图:

  1. 图是连通的,含有 个顶点与 条边;
  2. 边权是整数且在 内;
  3. 从点 到点 的最短路径长度是一个质数;
  4. 最小生成树的路径长度和为质数;
  5. 图上没有自环和重边。

给定 ,请构造出这样的图。

数据范围

题解

按照 的顺序连边,除了 的权为 ,其他边权都为 ,边 的程度根据总长度来凑出一个质数,这条链就是最小生成树。其他边只要边权大于这个最小生成树的最大边权,就随便加。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 100000 + 100;
  21. struct Node {
  22. int v, u;
  23. LL dis;
  24. Node() {}
  25. Node(int uu, int vv, LL d) {
  26. u = uu;
  27. v = vv;
  28. dis = d;
  29. }
  30. };
  31. int cnt, n, m;
  32. LL mst;
  33. LL maxlen;
  34. Node ans[maxn];
  35. int id[maxn];
  36. void add(int u, int v, int d) {
  37. ans[cnt].u = u;
  38. ans[cnt].v = v;
  39. ans[cnt++].dis = d;
  40. }
  41. bool isPrime(LL x) {
  42. for(LL i = 2; i * i <= x; ++i) {
  43. if(x % i == 0) {
  44. return false;
  45. }
  46. }
  47. return true;
  48. }
  49. int main() {
  50. #ifdef LOCAL
  51. freopen("test.txt", "r", stdin);
  52. // freopen("out.txt", "w", stdout);
  53. #endif // LOCAL
  54. ios::sync_with_stdio(false);
  55. while(scanf("%d%d", &n, &m) != EOF) {
  56. maxlen = 2;
  57. id[1] = n;
  58. for(int i = 2; i <= n; ++i) {
  59. id[i] = i - 1;
  60. }
  61. cnt = 0;
  62. add(1, n, 2);
  63. for(int i = 2; i < n; ++i) {
  64. add(id[i], id[i + 1], 1);
  65. }
  66. mst = n;
  67. while(!isPrime(mst)) {
  68. ++ans[cnt - 1].dis;
  69. ++mst;
  70. maxlen = max(maxlen, ans[cnt - 1].dis);
  71. }
  72. ++maxlen;
  73. for(int i = 1; i < n - 1; ++i) {
  74. for(int j = i + 2; j <= n; ++j) {
  75. if(cnt < m) {
  76. add(id[i], id[j], maxlen);
  77. } else {
  78. break;
  79. }
  80. }
  81. if(cnt >= m) {
  82. break;
  83. }
  84. }
  85. printf("%d %I64d\n", 2, mst);
  86. for(int i = 0; i < cnt; ++i) {
  87. printf("%d %d %I64d\n", ans[i].u, ans[i].v, ans[i].dis);
  88. }
  89. }
  90. return 0;
  91. }

E. Jamie and Tree

题意

题给一棵 个节点的树,每个节点上有一个权值 ,接下来有 次操作,按照以下输入进行相应操作:

  • : 将 作为树根;
  • : — 将包含有节点 的最小子树上的所有节点加上
  • : 询问以 为根的子树的所有节点的和。

对于每次询问,输出结果。

数据范围

题解

对于第 和第 种操作,就是裸的线段树构图 ,现在要考虑的是,根改变之后,节点 的根节点会如何改变。
如果记当前的根节点为 ,多画几组样例可以发现,对 两两求 序最大的,就是 为根时的子树的根,记为 ,对于 不在 的子树下的情况(以 为根节点),操作 直接对 对应的子树进行操作即可;如果 对应的子树下,就先对整棵树进行操作 ,再减去 所在的 的子树的贡献即可。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 100000 + 100;
  21. const int Log = 25;
  22. int root;
  23. int n, q, cnt, u, v, command;
  24. LL tmp, ans;
  25. LL num[maxn];
  26. int id[maxn], ide[maxn], rid[maxn];
  27. int fa[Log][maxn];
  28. vector<int> G[maxn];
  29. LL lazy[maxn << 2], sum[maxn << 2];
  30. void push_up(int rt) {
  31. sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
  32. }
  33. void push_down(int rt, int len) {
  34. if(lazy[rt]) {
  35. lazy[rt << 1] += lazy[rt];
  36. lazy[rt << 1 | 1] += lazy[rt];
  37. sum[rt << 1] += (len - (len >> 1)) * lazy[rt];
  38. sum[rt << 1 | 1] += (len >> 1) * lazy[rt];
  39. lazy[rt] = 0;
  40. }
  41. }
  42. void build(int l, int r, int rt) {
  43. lazy[rt] = 0;
  44. if(l == r) {
  45. sum[rt] = num[rid[l]];
  46. return ;
  47. }
  48. int m = (l + r) >> 1;
  49. build(l, m, rt << 1);
  50. build(m + 1, r, rt << 1 | 1);
  51. push_up(rt);
  52. }
  53. void add(int L, int R, LL tmp, int l, int r, int rt) {
  54. if(L <= l && r <= R) {
  55. lazy[rt] += tmp;
  56. sum[rt] += (r - l + 1) * tmp;
  57. return ;
  58. }
  59. push_down(rt, r - l + 1);
  60. int m = (r + l) >> 1;
  61. if(L <= m) {
  62. add(L, R, tmp, l, m, rt << 1);
  63. }
  64. if(R > m) {
  65. add(L, R, tmp, m + 1, r, rt << 1 | 1);
  66. }
  67. push_up(rt);
  68. }
  69. LL query(int L, int R, int l, int r, int rt) {
  70. if(L <= l && r <= R) {
  71. return sum[rt];
  72. }
  73. push_down(rt, r - l + 1);
  74. int m = (l + r) >> 1;
  75. LL ret = 0;
  76. if(L <= m) {
  77. ret += query(L, R, l, m, rt << 1);
  78. }
  79. if(R > m) {
  80. ret += query(L, R, m + 1, r, rt << 1 | 1);
  81. }
  82. return ret;
  83. }
  84. void dfs(int f, int x) {
  85. id[x] = ++cnt;
  86. rid[cnt] = x;
  87. int len = G[x].size();
  88. for(int i = 0; i < len; ++i) {
  89. int pos = G[x][i];
  90. if(pos != f) {
  91. fa[0][pos] = x;
  92. dfs(x, pos);
  93. }
  94. }
  95. ide[x] = cnt;
  96. }
  97. void prepare_skip_table() {
  98. cnt = 0;
  99. fa[0][1] = 1;
  100. dfs(1, 1);
  101. for(int j = 1; j < Log; ++j) {
  102. for(int i = 1; i <= n; ++i) {
  103. fa[j][i] = fa[j - 1][fa[j - 1][i]];
  104. }
  105. }
  106. }
  107. int Find(int x, int y, bool flag) {
  108. if(x == y) {
  109. return x;
  110. }
  111. if(id[x] > id[y]) {
  112. swap(x, y);
  113. }
  114. for(int i = Log - 1; i >= 0; --i) {
  115. if(id[fa[i][y]] > id[x]) {
  116. y = fa[i][y];
  117. }
  118. }
  119. if(flag) {
  120. return fa[0][y];
  121. } else {
  122. return y;
  123. }
  124. }
  125. int Find_real_root(int a, int b, int c) {
  126. int ret;
  127. int ab = Find(a, b, true);
  128. int ac = Find(a, c, true);
  129. if(id[ab] > id[ac]) {
  130. ret = ab;
  131. } else {
  132. ret = ac;
  133. }
  134. int bc = Find(b, c, true);
  135. if(id[ret] < id[bc]) {
  136. ret = bc;
  137. }
  138. return ret;
  139. }
  140. int main() {
  141. #ifdef LOCAL
  142. freopen("test.txt", "r", stdin);
  143. // freopen("out.txt", "w", stdout);
  144. #endif // LOCAL
  145. ios::sync_with_stdio(false);
  146. scanf("%d%d", &n, &q);
  147. for(int i = 1; i <= n; ++i) {
  148. scanf("%I64d", &num[i]);
  149. }
  150. for(int i = 1; i < n; ++i) {
  151. scanf("%d%d", &u, &v);
  152. G[u].push_back(v);
  153. G[v].push_back(u);
  154. }
  155. prepare_skip_table();
  156. build(1, n, 1);
  157. for(int i = 0; i < q; ++i) {
  158. scanf("%d", &command);
  159. if(command == 1) {
  160. scanf("%d", &u);
  161. root = u;
  162. } else if(command == 2) {
  163. scanf("%d%d%I64d", &u, &v, &tmp);
  164. int real_root = Find_real_root(u, v, root);
  165. if(real_root == root) {
  166. add(1, n, tmp, 1, n, 1);
  167. } else {
  168. if(id[real_root] < id[root] && ide[real_root] >= id[root]) {
  169. add(1, n, tmp, 1, n, 1);
  170. int rr = Find(real_root, root, false);
  171. add(id[rr], ide[rr], -tmp, 1, n, 1);
  172. } else {
  173. add(id[real_root], ide[real_root], tmp, 1, n, 1);
  174. }
  175. }
  176. } else {
  177. scanf("%d", &u);
  178. if(u == root) {
  179. printf("%I64d\n", query(1, n, 1, n, 1));
  180. } else {
  181. if(id[u] < id[root] && ide[u] >= id[root]) {
  182. ans = query(1, n, 1, n, 1);
  183. int rr = Find(u, root, false);
  184. ans -= query(id[rr], ide[rr], 1, n, 1);
  185. } else {
  186. ans = query(id[u], ide[u], 1, n, 1);
  187. }
  188. printf("%I64d\n", ans);
  189. }
  190. }
  191. }
  192. return 0;
  193. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注