[关闭]
@Dmaxiya 2019-01-15T19:59:04.000000Z 字数 9349 阅读 1193

Codeforces Round #531 (Div. 3)

Codeforces


Contests 链接:Codeforces Round #531 (Div. 3)
过题数:5
排名:176/9160

A. Integer Sequence Dividing

题意

给定一个整数 ,将 以内所有的整数分到两个集合 中,每个整数只能被分到一个集合,要求两个集合中所有数字的和的差的绝对值最小,即: 的值最小,其中空集合内所有数字的和为

输入

输入仅包含一个整数

输出

输出题目所求答案。

样例

输入
3
输出
0
提示
其中一种合法的分法是:令 ,这样
输入
5
输出
1
提示
其中一种合法的分法是:令 ,这样
输入
6
输出
1
提示
其中一种合法的分法是:令 ,这样

题解

通过多次枚举可以发现,如果 的整数倍,那么对于每 个数字,就可以用 将第 个和第 个分到一个集合中,剩下的分到另一个集合中,而对于 不是 的整数倍的情况,可以将多出来的 个数按照 时进行划分,就可以得到最小答案。

过题代码

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <cfloat>
  6. #include <climits>
  7. #include <iostream>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <algorithm>
  16. #include <bitset>
  17. #include <sstream>
  18. using namespace std;
  19. #define LL long long
  20. int n;
  21. int ans[10] = {0, 1, 1, 0};
  22. int main() {
  23. #ifdef Dmaxiya
  24. freopen("test.txt", "r", stdin);
  25. #endif // Dmaxiya
  26. ios::sync_with_stdio(false);
  27. while(scanf("%d", &n) != EOF) {
  28. printf("%d\n", ans[n % 4]);
  29. }
  30. return 0;
  31. }

B. Array K-Coloring

题意

给定 个整数 种颜色,要求用这 种颜色给所有整数上色,并且满足下面三个要求:

  1. 每个整数都必须要涂上一种颜色;
  2. 每种颜色至少要被涂上一次;
  3. 所有被颜色 涂上的数字都必须是不同的。

若存在满足上述条件的涂色方案,则输出任意一种,否则输出

输入

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

输出

如果不存在合法的解,则输出 ,否则在第一行输出 ,并在第二行给出任意一种合法的解,每种颜色用数字 内的整数表示。

样例

输入
4 2
1 2 2 3
输出
YES
1 1 2 2
提示
也是一种合法的涂色方案,当然也存在其他合法的涂色方案。
输入
5 2
3 2 1 2 3
输出
YES
2 1 1 2 1
提示
也是一种合法的涂色方案,当然也存在其他合法的涂色方案。
输入
5 2
2 1 1 2 1
输出
NO

题解

若存在任意一个颜色出现的次数大于 ,则输出 ,否则将每个数字 出现的位置存在一个 vector<int> 数组的第 个位置上,然后按下标从小到大遍历这个 vector<int> 数组,按 的循环给所有位置上色。

过题代码

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

C. Doors Breaking and Repairing

题意

有两个人玩一个游戏,最开始有 扇门,第 扇门初始的耐久性为 ,你是先手,另一个人后手,每当你选择一扇门,可以将这扇门的当前耐久度 改为 ,每当另一个人选择一扇门,若这扇门的当前耐久度不为 ,则可以将其修改为 ,你希望有最多的门的耐久度变为 ,而另一个人希望有最少的门的耐久度变为 ,两人都采取最优策略,问经过 轮游戏之后,最多有多少扇门的耐久度变为

输入

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

输出

输出题目所求答案。

样例

输入
6 3 2
2 3 1 3 4 2
输出
6
输入
5 3 3
1 2 4 2 3
输出
2
输入
5 5 6
1 2 6 10 3
输出
2

题解

,则先手一定能将所有门的耐久度都变为 ,否则若先手破坏一道 的门,后手就可以立即对第 扇门进行修复,所以先手只能去破坏 的门,而后手一定会去修复还没有被破坏的 的门,所以先手最多只能破坏 扇门,其中 的门的数量。

过题代码

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <cfloat>
  6. #include <climits>
  7. #include <iostream>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <algorithm>
  16. #include <bitset>
  17. #include <sstream>
  18. using namespace std;
  19. #define LL long long
  20. int n, x, y, num, cnt;
  21. int main() {
  22. #ifdef Dmaxiya
  23. freopen("test.txt", "r", stdin);
  24. #endif // Dmaxiya
  25. ios::sync_with_stdio(false);
  26. while(scanf("%d%d%d", &n, &x, &y) != EOF) {
  27. cnt = 0;
  28. for(int i = 0; i < n; ++i) {
  29. scanf("%d", &num);
  30. if(num <= x) {
  31. ++cnt;
  32. }
  33. }
  34. if(x > y) {
  35. printf("%d\n", n);
  36. continue;
  37. } else {
  38. printf("%d\n", (cnt + 1) / 2);
  39. }
  40. }
  41. return 0;
  42. }

D. Balanced Ternary String

题意

给定一个长度为 的三元字符串,字符串中只包含三种字符:0 1 2,每次可以将字符串中的一个字符替换成另一个字符,要求替换最少的次数,使得这个三元字符串每种字符的个数相等,如果有多种答案,输出字典序最小的一种。

输入

第一行包含一个整数 ,第二行为一个长度为 的三元字符串。

输出

输出题目所求答案。

样例

输入
3
121
输出
021
输入
6
000000
输出
001122
输入
6
211200
输出
211200
输入
6
120110
输出
120120

题解

先统计字符 0 1 2 出现的次数 ,然后先从前往后确定所有 的位置,若 ,则将前 标为 ,表示完全确定,并且不能更改,多出来的 0,表示可以更改,若 ,则将靠前的非 0 值大于 的字符改为 0,并修改相应的 值,并将该位置标为 ,对于 12 也是如此。

过题代码

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

E. Monotonic Renumeration

题意

给定一个长度为 的序列 ,要求生成一个满足以下条件的序列

  1. 对于任意的 ,若 ,则 (若 ,也可以使得 );
  2. 对于每一个 ,有 或者

统计总共有多少种 序列满足条件,将答案对 取模后输出。

输入

第一行包含一个整数 ,第二行包含 个整数

输出

输出题目所求答案。

样例

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

题解

可知若存在 ,则对于任意 ,有 ,因此所有 个整数被分为 个区间,每个区间内的 值都必须相等,答案就是
先记录每个数字 最后出现的下标 ,然后将 扫一遍,在扫的过程中将所有 的值更新到 中,直到停止扫描,则刚刚扫过的整个区间的 的值都必须相同。即上述的 个区间中的其中一个。

过题代码

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

F. Elongated Matrix

题意

有一个 的矩阵,可以对这个矩阵进行交换任意两行的操作(也可以不进行任何操作),但是列的顺序不能被交换,要求交换完毕后,将最后的矩阵进行按列扫描(即按 的顺序扫描),得到一个序列 ,序列 的任意相邻两项之间满足 ,求最大的 值。

输入

第一行为两个整数 ,接下去 行每行 个整数,第 行第 列的整数 表示矩阵对应位置的整数,其中

输出

输出题目所求答案。

样例

输入
4 2
9 9
10 8
5 3
4 3
输出
5
提示
将矩阵按行交换成如下矩阵,即可得到最大的
5 3
10 8
4 3
9 9
此时 序列为:,任意两个相邻元素之间的差值至少为
输入
2 4
1 2 3 4
10 3 7 3
输出
0
提示
将行按任意顺序排列,得到的 值都为
输入
6 1
3
6
2
5
1
4
输出
3
提示
原序列的 值已经为

题解

由于对于任意两行 ,只要 的下一行,那么这两行中任意一列的差值都是定值,且从第 行到第 行的距离必然为 ,因此可以将 列处理成 列,不考虑跨列连接的问题的话,就变成了 列的问题了。
定义 表示以第 行为起点,第 列为终点, 的二进制位中所有为 的位都被访问过的状态的最大满足条件的距离,假设从 到中转行 的遍历行数的状态为 ,那么到达一个新的行 的距离,可以用状态转移方程得到:

其中 表示 的第 个二进制位的值。 的初始值为

最后考虑跨列的情况,即以 为起始行, 为最终行,从 行的当前列到 行的下一列,其距离为:,将所有 与对应的 ,再取所有的最大值,就是答案。
注意特判 的情况。

过题代码

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <cfloat>
  6. #include <climits>
  7. #include <iostream>
  8. #include <string>
  9. #include <vector>
  10. #include <list>
  11. #include <queue>
  12. #include <stack>
  13. #include <map>
  14. #include <set>
  15. #include <algorithm>
  16. #include <bitset>
  17. #include <sstream>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 16;
  21. const int maxm = 10000 + 100;
  22. int n, m;
  23. int num[maxn][maxm];
  24. int dp[maxn][maxn][1 << maxn];
  25. int dis[maxn][maxn], dis_next[maxn][maxn];
  26. int main() {
  27. #ifdef Dmaxiya
  28. freopen("test.txt", "r", stdin);
  29. #endif // Dmaxiya
  30. ios::sync_with_stdio(false);
  31. while(scanf("%d%d", &n, &m) != EOF) {
  32. for(int i = 0; i < n; ++i) {
  33. for(int j = 0; j < m; ++j) {
  34. scanf("%d", &num[i][j]);
  35. }
  36. }
  37. if(n == 1) {
  38. int ans = INT_MAX;
  39. for(int i = 1; i < m; ++i) {
  40. ans = min(ans, abs(num[0][i] - num[0][i - 1]));
  41. }
  42. printf("%d\n", ans);
  43. continue;
  44. }
  45. for(int i = 0; i < n; ++i) {
  46. for(int j = 0; j < n; ++j) {
  47. dis[i][j] = INT_MAX;
  48. dis_next[i][j] = INT_MAX;
  49. if(i == j) {
  50. continue;
  51. }
  52. for(int k = 0; k < m; ++k) {
  53. dis[i][j] = min(dis[i][j], abs(num[i][k] - num[j][k]));
  54. if(k != 0) {
  55. dis_next[i][j] = min(dis_next[i][j], abs(num[i][k - 1] - num[j][k]));
  56. }
  57. }
  58. }
  59. }
  60. memset(dp, 0, sizeof(dp));
  61. for(int i = 0; i < n; ++i) {
  62. dp[i][i][1 << i] = INT_MAX;
  63. }
  64. for(int i = 1; i < (1 << n); ++i) {
  65. for(int s = 0; s < n; ++s) {
  66. if(((i >> s) & 1) == 0) {
  67. continue;
  68. }
  69. for(int t = 0; t < n; ++t) {
  70. if(s == t || ((i >> t) & 1) == 1) {
  71. continue;
  72. }
  73. for(int j = 0; j < n; ++j) {
  74. if(((i >> j) & 1) == 0) {
  75. continue;
  76. }
  77. int tmp = i | (1 << t);
  78. dp[s][t][tmp] = max(dp[s][t][tmp], min(dp[s][j][i], dis[j][t]));
  79. }
  80. }
  81. }
  82. }
  83. int ans = 0;
  84. int tmp = (1 << n) - 1;
  85. for(int i = 0; i < n; ++i) {
  86. for(int j = 0; j < n; ++j) {
  87. if(i == j) {
  88. continue;
  89. }
  90. ans = max(ans, min(dp[i][j][tmp], dis_next[j][i]));
  91. }
  92. }
  93. printf("%d\n", ans);
  94. }
  95. return 0;
  96. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注