[关闭]
@Dmaxiya 2018-08-17T10:21:46.000000Z 字数 10714 阅读 1025

Codeforces Round #496 (Div. 3)

Codeforces


Contests 链接:Codeforces Round #496 (Div. 3)
过题数:5
排名:237/7632

A. Tanya and Stairways

题意

在上楼梯的时候会一阶一阶地数,当她上一个 阶的楼梯时,她会数 ,到达第二层时,她会同样地一阶一阶地数上去,现在已经知道她数的 个数字,问她走的每一层有多少个台阶。

输入

第一行为一个整数 ,第二行为 个整数 ,表示 数的每个数字,数据保证合法。

输出

第一行为一个整数 ,表示 上的楼层数,第二行为 个整数 ,表示 上的每层的台阶数量。

样例

输入 输出
7
1 2 3 1 2 3 4
2
3 4
4
1 1 1 1
4
1 1 1 1
5
1 2 3 4 5
1
5
5
1 2 1 2 1
3
2 2 1

题解

每次数到 的时候,输出 前面的数字。

过题代码

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

B. Delete from the Left

题意

给定两个字符串 ,问至少将这两个字符串从前面往后面删掉多少个字符,才能使得两个字符串相等,空字符串与空字符串也是相等的。

输入

输入为两行字符串 ,且两个字符串都只包含小写字母。

输出

输出最少需要删除的前缀字符数量。

样例

输入 输出 提示
test
west
2 应该将两个字符串都删除到只剩下 ,这样需要删除 个字符。
codeforces
yes
9 应该将两个字符串都删除到只剩下 ,第一个字符串被删了 个字符而第二个字符串被删了 个字符。
test
yes
7 应该将两个字符串都删除到空,总共要删除 个字符。
b
ab
1 删除掉第二个字符串的 ,就可以让两个字符串相等。

题解

从后往前找两个字符串的最长公共后缀,如果后缀长度为 ,最少需要删除的字符数量就是

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 200000 + 100;
  23. int len1, len2;
  24. char s[maxn], t[maxn];
  25. int main() {
  26. #ifdef LOCAL
  27. freopen("test.txt", "r", stdin);
  28. // freopen("out.txt", "w", stdout);
  29. #endif
  30. ios::sync_with_stdio(false);
  31. while(scanf("%s%s", s, t) != EOF) {
  32. len1 = strlen(s);
  33. len2 = strlen(t);
  34. int Min = min(len1, len2);
  35. int ans = Min;
  36. for(int i = 1; i <= Min; ++i) {
  37. if(s[len1 - i] != t[len2 - i]) {
  38. ans = i - 1;
  39. break;
  40. }
  41. }
  42. printf("%d\n", len1 + len2 - ans * 2);
  43. }
  44. return 0;
  45. }

C. Summarize to the Power of Two

题意

定义一个长度为 的序列 为好的序列,当且仅当对于序列中的每一个整数 ,都可以找到一个对应的数字 ,使得 的整数次幂,一个空的序列也是一个好的序列。现在给定一个长度为 的序列 ,问最少删除多少个数字,可以使这个序列成为一个好的序列。

输入

第一行为一个整数 ,第二行为 个整数

输出

输出最少要删除的数字个数。

样例

输入 输出 提示
6
4 7 1 5 4 9
1 删除第 个数字 ,剩下的序列 就是一个好的序列。
5
1 2 3 4 5
2
1
16
1
4
1 1 1 1023
0

题解

对于序列中的每个数字,都枚举 ,查找序列中是否存在另一个数字等于 ,如果存在,则这个数字不需要删除,否则就需要删除这个数字,统计需要删除的数字个数。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 120000 + 100;
  23. int n;
  24. LL num[maxn], two[50];
  25. set<LL> st;
  26. map<LL, int> mp;
  27. map<LL, int>::iterator it, itt;
  28. int main() {
  29. #ifdef LOCAL
  30. freopen("test.txt", "r", stdin);
  31. // freopen("out.txt", "w", stdout);
  32. #endif
  33. ios::sync_with_stdio(false);
  34. for(int i = 0; i <= 31; ++i) {
  35. two[i] = (1LL << i);
  36. }
  37. while(scanf("%d", &n) != EOF) {
  38. mp.clear();
  39. st.clear();
  40. for(int i = 0; i < n; ++i) {
  41. scanf("%I64d", &num[i]);
  42. ++mp[num[i]];
  43. }
  44. for(it = mp.begin(); it != mp.end(); ++it) {
  45. for(int j = 0; j <= 31; ++j) {
  46. itt = mp.find(two[j] - it->first);
  47. if(itt != mp.end()) {
  48. if(itt->first != it->first) {
  49. st.insert(it->first);
  50. break;
  51. } else {
  52. if(itt->second != 1) {
  53. st.insert(it->first);
  54. break;
  55. }
  56. }
  57. }
  58. }
  59. }
  60. int ans = 0;
  61. for(it = mp.begin(); it != mp.end(); ++it) {
  62. if(st.find(it->first) == st.end()) {
  63. ans += it->second;
  64. }
  65. }
  66. printf("%d\n", ans);
  67. }
  68. return 0;
  69. }

D. Polycarp and Div 3

题意

给定一个大整数,将这个大整数进行分割,使得被分割的每一部分除了 以外都不含前导零,且都能被 整除,问最多能分割成多少部分。

输入

输入为一个正整数 的长度在 之间,最左边的数字保证不为

输出

输出能够切割的合法的最大段数。

样例

输入 输出 提示
3121 2 一种合法的切割方式为
6 1 一位数字无法切割,且这个数字能被 整除,所以答案为
1000000000000000000000000000000000 33 应该在每位数字之间进行分割,这样将会得到一个 以及
201920181 4 一种合法的分割为 ,其中有 段数字能够被 整除。

题解

先将每位数字对 取模后得到一个新的数字串,然后从前往后进行贪心,只要碰到 ,就直接进行分割,就能得到最优解。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 200000 + 100;
  23. int len, ans;
  24. int num[maxn];
  25. char str[maxn];
  26. int main() {
  27. #ifdef LOCAL
  28. freopen("test.txt", "r", stdin);
  29. // freopen("out.txt", "w", stdout);
  30. #endif
  31. ios::sync_with_stdio(false);
  32. while(scanf("%s", str) != EOF) {
  33. len = strlen(str);
  34. for(int i = 0; i < len; ++i) {
  35. num[i] = (str[i] - '0') % 3;
  36. }
  37. ans = 0;
  38. for(int i = 0; i < len; ++i) {
  39. if(num[i] == 0) {
  40. ++ans;
  41. continue;
  42. }
  43. if(i + 1 < len && num[i] == 2 && num[i + 1] == 1) {
  44. ++ans;
  45. ++i;
  46. continue;
  47. }
  48. if(i + 1 < len && num[i] == 1 && num[i + 1] == 2) {
  49. ++ans;
  50. ++i;
  51. continue;
  52. }
  53. if(i + 2 < len && num[i] == 1 && num[i + 1] == 1 && num[i + 2] == 1) {
  54. ++ans;
  55. i += 2;
  56. }
  57. if(i + 2 < len && num[i] == 2 && num[i + 1] == 2 && num[i + 2] == 2) {
  58. ++ans;
  59. i += 2;
  60. }
  61. }
  62. printf("%d\n", ans);
  63. }
  64. return 0;
  65. }

E1. Median on Segments (Permutations Edition)

题意

给定一个 的排列 ,问这个序列有多少个区间满足中位数等于 的条件。
其中中位数的定义为:对于长度为奇数的序列,将这个序列按从小到大排序后中间的数字就是中位数,对于长度为偶数的序列,将这个序列按从小到大排序后,取中间两个数中小的那个数就是中位数。

输入

第一行为两个整数 ,第二行为 的排列

输出

输出满足条件的区间的个数。

样例

输入 输出 提示
5 4
2 4 5 3 1
4 满足条件的区间为:.
5 5
1 2 3 4 5
1
15 8
1 15 2 14 3 13 4 8 12 5 11 6 10 7 9
48

题解

所有满足条件的区间一定都包含数字 ,所以这些区间的左端点一定在 左边,右端点一定在 的右边,先统计 的右边 的值,再对于 的左边的每个端点,计算有多少个右端点满足 (区间长度为奇数的情况) 以及 (区间长度为偶数的情况),将所有满足条件的区间个数求和就是答案。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 200000 + 100;
  23. int n, m, Index;
  24. int num[maxn], cnt[2];
  25. map<int, int> mp;
  26. int main() {
  27. #ifdef LOCAL
  28. freopen("test.txt", "r", stdin);
  29. // freopen("out.txt", "w", stdout);
  30. #endif
  31. ios::sync_with_stdio(false);
  32. while(scanf("%d%d", &n, &m) != EOF) {
  33. mp.clear();
  34. memset(cnt, 0, sizeof(cnt));
  35. ++mp[0];
  36. for(int i = 1; i <= n; ++i) {
  37. scanf("%d", &num[i]);
  38. if(num[i] == m) {
  39. Index = i;
  40. }
  41. if(num[i] > m) {
  42. num[i] = 1;
  43. } else {
  44. num[i] = 0;
  45. }
  46. }
  47. for(int i = Index + 1; i <= n; ++i) {
  48. ++cnt[num[i]];
  49. ++mp[cnt[0] - cnt[1]];
  50. }
  51. memset(cnt, 0, sizeof(cnt));
  52. LL ans = mp[0] + mp[-1];
  53. for(int i = Index - 1; i > 0; --i) {
  54. ++cnt[num[i]];
  55. if(mp.find(cnt[1] - cnt[0]) != mp.end()) {
  56. ans += mp[cnt[1] - cnt[0]];
  57. }
  58. if(mp.find(cnt[1] - cnt[0] - 1) != mp.end()) {
  59. ans += mp[cnt[1] - cnt[0] - 1];
  60. }
  61. }
  62. printf("%I64d\n", ans);
  63. }
  64. return 0;
  65. }

E2. Median on Segments (General Case Edition)

题意

给定一个长度为 的序列 ,问这个序列有多少个区间满足中位数等于 的条件。中位数的定义同 E1 题。

输入

第一行为两个整数 ,第二行为 个整数

输出

输出满足条件的区间的个数。

样例

输入 输出 提示
5 4
1 4 5 60 4
8 满足条件的区间为:
3 1
1 1 1
6
15 2
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
97

题解

如果将所有大于等于 的数字标记为 ,所有小于 的数字标记为 ,那么对于任意一个区间,这个区间的中位数大于等于 当且仅当区间和大于 ,对 做相同的操作,则答案为
求解 的方法为:对这个只包含 的数组,从前往后扫描,扫描到第 个数字的前缀和 时,统计有多少个 满足条件 ,即有多少个区间和大于 ,统计满足条件的前缀和个数可以用树状数组维护。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 200000 + 100;
  23. LL n, m, nn, Sum;
  24. LL num[maxn], numtmp[maxn];
  25. LL sum[maxn << 1];
  26. int id(int x) {
  27. return x + maxn;
  28. }
  29. int lowbit(int x) {
  30. return x & (-x);
  31. }
  32. void update(int Index, int x) {
  33. while(Index <= nn) {
  34. sum[Index] += x;
  35. Index += lowbit(Index);
  36. }
  37. }
  38. int query(int Index) {
  39. int ret = 0;
  40. while(Index != 0) {
  41. ret += sum[Index];
  42. Index -= lowbit(Index);
  43. }
  44. return ret;
  45. }
  46. LL solve(LL m) {
  47. memset(sum, 0, sizeof(sum));
  48. LL ret = 0;
  49. Sum = 0;
  50. update(id(0), 1);
  51. for(int i = 1; i <= n; ++i) {
  52. int tmp = 1;
  53. if(num[i] < m) {
  54. tmp = -1;
  55. }
  56. Sum += tmp;
  57. ret += query(id(Sum) - 1);
  58. update(id(Sum), 1);
  59. }
  60. return ret;
  61. }
  62. int main() {
  63. #ifdef LOCAL
  64. freopen("test.txt", "r", stdin);
  65. // freopen("out.txt", "w", stdout);
  66. #endif
  67. ios::sync_with_stdio(false);
  68. nn = maxn * 2 - 1;
  69. while(scanf("%I64d%I64d", &n, &m) != EOF) {
  70. for(int i = 1; i <= n; ++i) {
  71. scanf("%I64d", &num[i]);
  72. }
  73. printf("%I64d\n", solve(m) - solve(m + 1));
  74. }
  75. return 0;
  76. }

F. Berland and the Shortest Paths

题意

在一个 个节点 条边的无向图中,选出 条边,使得这些边能构成一个节点为 的树,假设树上每个节点到节点 的最短路为 ,则要使构造出来的树满足 最小,输出 中选边的方案,如果总的合法方案数少于 种,则直接输出所有方案。

输入

第一行为三个整数 ,接下去 行每行两个整数 ,表示图上的 条边,图保证连通。

输出

第一行为将要输出的方案数 ,如果总的方案数大于 ,则只要输出任意 个方案,否则输出所有方案,接下去 行每行为一个 字符串,第 位为 表示不选第 条边,为 表示选择这条边,数据保证

样例

输入 输出
4 4 3
1 2
2 3
1 4
4 3
2
1110
1011
4 6 3
1 2
2 3
1 4
4 3
2 4
1 3
1
101001
5 6 2
1 2
1 3
2 4
2 5
3 4
3 5
2
111100
110110

题解

首先对这张图从 开始进行一次 ,计算每个点到达 的最短距离 ,对于第 个节点,查找与其相连的所有节点中, 的节点,这些节点一定可以作为节点 的父节点(在生成的树中),每个节点的前缀节点个数为 ,则所有的方案数为 ,注意所有方案数可能会爆

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cfloat>
  7. #include <cstring>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <bitset>
  16. #include <algorithm>
  17. #include <ctime>
  18. #include <functional>
  19. #include <iomanip>
  20. using namespace std;
  21. #define LL long long
  22. const int maxn = 200000 + 100;
  23. const int maxm = 1000000 + 100;
  24. struct Node {
  25. int pos, Index;
  26. Node() {}
  27. Node(int p, int I) {
  28. pos = p;
  29. Index = I;
  30. }
  31. };
  32. int INF;
  33. LL ans;
  34. int n, m, k, u, v;
  35. int dis[maxn];
  36. char str[maxm];
  37. vector<Node> G[maxn], pre[maxn];
  38. queue<int> que;
  39. void bfs() {
  40. dis[1] = 0;
  41. que.push(1);
  42. while(!que.empty()) {
  43. int tmp = que.front();
  44. que.pop();
  45. int len = G[tmp].size();
  46. for(int i = 0; i < len; ++i) {
  47. int pos = G[tmp][i].pos;
  48. if(dis[pos] == INF) {
  49. dis[pos] = dis[tmp] + 1;
  50. que.push(pos);
  51. }
  52. }
  53. }
  54. }
  55. void dfs(int depth) {
  56. if(depth == n + 1) {
  57. printf("%s\n", str + 1);
  58. --ans;
  59. return ;
  60. }
  61. int len = pre[depth].size();
  62. for(int i = 0; i < len; ++i) {
  63. str[pre[depth][i].Index] = '1';
  64. dfs(depth + 1);
  65. str[pre[depth][i].Index] = '0';
  66. if(ans <= 0) {
  67. return ;
  68. }
  69. }
  70. }
  71. int main() {
  72. #ifdef LOCAL
  73. freopen("test.txt", "r", stdin);
  74. // freopen("out.txt", "w", stdout);
  75. #endif
  76. ios::sync_with_stdio(false);
  77. memset(&INF, 0x3f, sizeof(INF));
  78. while(scanf("%d%d%d", &n, &m, &k) != EOF) {
  79. ans = 1;
  80. memset(str, '0', sizeof(str));
  81. str[m + 1] = '\0';
  82. for(int i = 1; i <= n; ++i) {
  83. dis[i] = INF;
  84. G[i].clear();
  85. pre[i].clear();
  86. }
  87. for(int i = 1; i <= m; ++i) {
  88. scanf("%d%d", &u, &v);
  89. G[u].push_back(Node(v, i));
  90. G[v].push_back(Node(u, i));
  91. }
  92. bfs();
  93. for(int i = 2; i <= n; ++i) {
  94. int len = G[i].size();
  95. for(int j = 0; j < len; ++j) {
  96. int pos = G[i][j].pos;
  97. if(dis[pos] == dis[i] - 1) {
  98. pre[i].push_back(Node(pos, G[i][j].Index));
  99. }
  100. }
  101. }
  102. for(int i = 2; i <= n; ++i) {
  103. ans *= (LL)pre[i].size();
  104. if(ans > k) {
  105. ans = k;
  106. break;
  107. }
  108. }
  109. ans = min(ans, (LL)k);
  110. printf("%I64d\n", ans);
  111. dfs(2);
  112. }
  113. return 0;
  114. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注