[关闭]
@Dmaxiya 2018-08-17T10:23:31.000000Z 字数 8014 阅读 1109

Codeforces Round #493 (Div. 2)

Codeforces


Contests 链接:Codeforces Round #493 (Div. 2)
过题数:4
排名:47/5210

A. Balloons

题意

总共有 个袋子,第 个袋子里放 个气球,现在要把所有的袋子分成非空的两部分,要求第一部分的气球总数不等于第二部分的气球总数,输出合法的分配方案。

输入

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

输出

如果无法将所有袋子分成合法的两部分,输出 ,否则在第一行输出一个整数 ,表示分给第一部分的袋子数,接下去一行为 个整数,表示将编号为 的袋子分到第一部分,如果有多解输出任意一组。

样例

输入 输出 提示
3
1 2 1
2
1 2
第一部分有 个气球而第二部分有 个气球。
2
5 5
-1 只有一种分法:第一个袋子分给第一部分,第二个袋子分给第二部分,而这种分法将使得
第一部分的气球数量等于第二部分的气球。
1
10
-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 = 100 + 100;
  23. int n, sum, Min;
  24. int num[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. sum = 0;
  33. Min = 1;
  34. for(int i = 1; i <= n; ++i) {
  35. scanf("%d", &num[i]);
  36. if(num[i] < num[Min]) {
  37. Min = i;
  38. }
  39. sum += num[i];
  40. }
  41. if(n == 1) {
  42. printf("-1\n");
  43. continue;
  44. }
  45. if(sum - num[Min] == num[Min]) {
  46. printf("-1\n");
  47. } else {
  48. printf("1\n%d\n", Min);
  49. }
  50. }
  51. return 0;
  52. }

B. Cutting

题意

给定一个长度为 的数列,这个数列的奇数项的个数和偶数项的个数相等,将这个数列分割成多个数列,要让每个数列的奇数项个数都等于偶数项个数,如果在数列中的两个数字 之间分割,将花费 个比特币,问在满足花费不超过 个比特币的情况下,最多可以分割多少次。

输入

第一行包含两个整数 ,第二行包含 个整数 ,其中奇数项的个数一定等于偶数项的个数。

输出

输出满足条件的最大分割次数。

样例

输入 输出 提示
6 4
1 2 5 10 15 20
1 最优的分割方式是在 之间,分割的花费为
4 10
1 3 2 4
0 没有任何位置可以进行分割。
6 100
1 2 3 4 5 6
2 可以在 之间进行分割,花费为

题解

首先预处理出每个可以分割的位置以及花费,将所有花费按从小到大排序,贪心地每次取花费最小的点进行分割,就能得到最多的分割次数。

过题代码

  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 = 100 + 100;
  23. int n, B, tmp, cnt;
  24. int num[maxn], sum[maxn];
  25. int *it;
  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, &B) != EOF) {
  33. for(int i = 0; i < n; ++i) {
  34. scanf("%d", &num[i]);
  35. }
  36. tmp = 0;
  37. cnt = 0;
  38. for(int i = 0; i < n - 1; ++i) {
  39. if(num[i] % 2 == 0) {
  40. ++tmp;
  41. } else {
  42. --tmp;
  43. }
  44. if(tmp == 0) {
  45. sum[cnt++] = abs(num[i] - num[i + 1]);
  46. }
  47. }
  48. sort(sum, sum + cnt);
  49. for(int i = 1; i < cnt; ++i) {
  50. sum[i] += sum[i - 1];
  51. }
  52. it = upper_bound(sum, sum + cnt, B);
  53. printf("%d\n", it - sum);
  54. }
  55. return 0;
  56. }

C. Convert to Ones

题意

对一个长度为 字符串,可以进行以下两种操作:

  1. 选择其中一个子串(也可以选择整个字符串),将这个子串翻转,这将花费 元,例如:
  2. 选择其中一个子串,将这个子串中所有的 变为 ,所有 变为 ,这将花费 元,例如:

以上操作可以以任意顺序执行,问要将一个给定的 字符串通过以上两种操作转化为全为 的字符串,最小的花费是多少?

输入

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

输出

输出最少花费。

样例

输入 输出 提示
5 1 10
01000
11 首先你需要对子串 进行操作 ,然后对子串 进行操作 ,字符串变化过程为:

总的花费为
5 10 1
01000
2 首先你需要对子串 进行操作 ,然后对子串 进行操作 ,字符串的变化过程为:

总的花费为
7 2 3
1111111
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 = 300000 + 100;
  23. bool flag;
  24. LL n, x, y, len, cnt, ans;
  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("%I64d%I64d%I64d", &n, &x, &y) != EOF) {
  33. ans = 1e18;
  34. cnt = 0;
  35. flag = false;
  36. scanf("%s", str);
  37. len = strlen(str);
  38. for(int i = 0; i <= len; ++i) {
  39. if(str[i] != '0') {
  40. if(flag) {
  41. ++cnt;
  42. flag = false;
  43. }
  44. } else {
  45. flag = true;
  46. }
  47. }
  48. if(cnt == 0) {
  49. printf("0\n");
  50. continue;
  51. }
  52. for(LL i = 1; i <= cnt; ++i) {
  53. ans = min(ans, i * y + (cnt - i) * x);
  54. }
  55. printf("%I64d\n", ans);
  56. }
  57. return 0;
  58. }

D. Roman Digits

题意

在罗马数字和阿拉伯数字之间存在映射:,对于任意一个由罗马数字组成的数字,它表示的数值等于每一位对应映射的和,如:,注意这里的表达方式和一般的罗马数字的表达方式不同, 的值为 而不是 ,如果现在有一个 位的罗马数字,问这个罗马数字表示的值有几种可能的情况?

输入

输入只包含一个整数

输出

输出为一个整数,表示用 位罗马数字能够表示的不同的数字的个数。

样例

输入 输出 提示
1 4 可以表示的数字为:
2 10 可以表示的数字为:
10 244

题解

通过暴力打表找规律到第 项可以发现,除了前 项是没有规律的,第 项开始就是一个公差为 的等差数列。

过题代码

  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. LL n;
  23. LL num[15] = {0, 4, 6, 10, 15, 21, 27, 33, 39, 43, 46, 48};
  24. int main() {
  25. #ifdef LOCAL
  26. freopen("test.txt", "r", stdin);
  27. // freopen("out.txt", "w", stdout);
  28. #endif
  29. ios::sync_with_stdio(false);
  30. for(int i = 1; i <= 11; ++i) {
  31. num[i] += num[i - 1];
  32. }
  33. while(scanf("%I64d", &n) != EOF) {
  34. if(n <= 11) {
  35. printf("%I64d\n", num[n]);
  36. continue;
  37. }
  38. printf("%I64d\n", 292LL + 49LL * (n - 11));
  39. }
  40. return 0;
  41. }

E. Sky Full of Stars

题意

在一个 的网格中,可以给每一格方格填充红、绿、蓝中的一种颜色,则总共有 种涂色方案,问在这些方案中,至少有一行或者一列颜色相同的涂色方案数。

输入

输入只包含一个整数

输出

输出所有合法的涂色方案数对 取模的结果。

样例

输入 输出 提示
1 3 由于只有一行一列,因此所有涂色方案都是合法的,总共有 种涂色方案。
2 63 时,以下两种涂色方案是合法的:

而以下两种涂色方案是不合法的:
3 9933

题解

首先计算某几行以及某几列颜色相同的情况,如:


在这些情况中,颜色相同的所有行和列都为同一种颜色的情况会被重复计算如:

这些情况在计算行时会计算一次,计算列时又计算了一次,因此要减去这些情况。
首先来计算某几行颜色相同的情况,由容斥原理可以知道,某几行颜色相同的情况等于至少一行颜色相同的情况,减去至少两行颜色相同的情况,加上至少三行颜色相同的情况……而至少 行颜色相同的方案数为 ,因此某几行颜色相同的方案数为:

某几列的计算方式与某几行的计算方式完全相同,所以直接将上式乘 ,即可得到某几行颜色相同与某几列颜色相同的方案数的和,而接下来要减去某几行与某几列颜色完全相同的情况。
同样地,这也是一个容斥,对于每一个 行去枚举 列,就是有 行至少一列颜色相同的情况,减去有 行至少两列颜色相同的情况,加上 行至少 列颜色相同的情况……在枚举 行的时候也是同样的容斥。如果至少有 列的颜色完全相同,那么所有的方案数为 ,因此某几行某几列颜色完全相同的方案数为:

这个公式计算的复杂度为 ,因此需要化简,可以发现其中隐含了二项式 ,对于每个固定的 ,将关于 的项化简可以得到:

最终的结果就是:

这个公式本身的计算次数是 的,但是由于存在幂次,所以应该用快速幂将幂运算的时间复杂度降低到 ,因此总的时间复杂度为

过题代码

  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 LL MOD = 998244353;
  23. const int maxn = 1000000 + 100;
  24. LL n, ans;
  25. LL inv[maxn], pro[maxn], invpro[maxn];
  26. void Prepare_C() {
  27. inv[1] = 1;
  28. for(int i = 2; i < maxn; ++i) {
  29. inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
  30. }
  31. pro[0] = invpro[0] = 1;
  32. for(int i = 1; i < maxn; ++i) {
  33. pro[i] = pro[i - 1] * i % MOD;
  34. invpro[i] = invpro[i - 1] * inv[i] % MOD;
  35. }
  36. }
  37. LL get_C(LL n, LL m) {
  38. if(n < m) {
  39. return 0;
  40. }
  41. return pro[n] * invpro[m] % MOD * invpro[n - m] % MOD;
  42. }
  43. LL fast_pow(LL x, LL n) {
  44. LL ans;
  45. for(ans = 1; n != 0; n >>= 1) {
  46. if((n & 1) == 1) {
  47. ans = (ans * x) % MOD;
  48. }
  49. x = (x * x) % MOD;
  50. }
  51. return ans;
  52. }
  53. int main() {
  54. #ifdef LOCAL
  55. freopen("test.txt", "r", stdin);
  56. // freopen("out.txt", "w", stdout);
  57. #endif
  58. ios::sync_with_stdio(false);
  59. Prepare_C();
  60. while(scanf("%I64d", &n) != EOF) {
  61. ans = 0;
  62. for(LL i = 1; i <= n; ++i) {
  63. LL first = 1;
  64. LL second = 1;
  65. if(i % 2 == 0) {
  66. first = (-1 * first % MOD + MOD) % MOD;
  67. second = first;
  68. }
  69. first = 2 * first % MOD * get_C(n, i) % MOD * fast_pow(3, (n - i) * n + i) % MOD;
  70. LL tmp = ((fast_pow(3, n - i) - 1) % MOD + MOD) % MOD;
  71. tmp = ((fast_pow(tmp, n) - fast_pow(3, (n - i) * n)) % MOD + MOD) % MOD;
  72. second = 3 * second % MOD * get_C(n, i) % MOD * tmp % MOD;
  73. ans = (ans + first + second) % MOD;
  74. }
  75. printf("%I64d\n", ans);
  76. }
  77. return 0;
  78. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注