[关闭]
@Dmaxiya 2018-08-17T10:26:23.000000Z 字数 7824 阅读 933

Codeforces Round #489 (Div. 2)

Codeforces


Contests 链接:Codeforces Round #489 (Div. 2)
过题数:3
排名:289/6253

A. Nastya and an Array

题意

有一个长度为 的序列,每一秒她可以将这个序列上的所有非零的数字加上同一个数字,如果这个序列所有的数字都等于 ,那么这个序列就爆炸了,问最少需要多少秒,能够使这个序列爆炸。

输入

第一行包含一个整数 ,第二行包含 个整数 表示这个序列中的每一个数字。

输出

一个整数,表示最少能够使这个序列爆炸的时间。

样例

输入 输出
5
1 1 1 1 1
1
3
2 0 -1
2
4
5 -6 -5 1
4

题解

直接判断序列中有多少个不同的非零数字。

过题代码

  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. typedef long long LL;
  20. int n, x;
  21. set<int> st;
  22. int main() {
  23. #ifdef Dmaxiya
  24. freopen("test.txt", "r", stdin);
  25. // freopen("test1.out", "w", stdout);
  26. #endif // Dmaxiya
  27. ios::sync_with_stdio(false);
  28. while(scanf("%d", &n) != EOF) {
  29. st.clear();
  30. for(int i = 0; i < n; ++i) {
  31. scanf("%d", &x);
  32. if(x != 0) {
  33. st.insert(x);
  34. }
  35. }
  36. int ans = st.size();
  37. printf("%d\n", ans);
  38. }
  39. return 0;
  40. }

B. Nastya Studies Informatics

题意

定义一对好的整数,这对整数必须满足 ,问在区间 内,有多少对好的整数。如果 ,则 被认为是不同的整数对。

输入

输入包含四个整数

输出

输出问题的答案。

样例

输入 输出
1 2 1 2 2
1 12 1 12 4
50 100 3 30 0

题解

要满足 ,首先必须满足 ,否则不存在满足要求的整数对。设 ,则 ,所以 ,因此问题就转化为求在区间 内的 的因子对 的个数,其中 地枚举即可。

过题代码

  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. typedef long long LL;
  20. int l, r, x, y, ans;
  21. int gcd(int a, int b) {
  22. return b == 0? a: gcd(b, a % b);
  23. }
  24. int main() {
  25. #ifdef Dmaxiya
  26. freopen("test.txt", "r", stdin);
  27. // freopen("test1.out", "w", stdout);
  28. #endif // Dmaxiya
  29. ios::sync_with_stdio(false);
  30. while(scanf("%d%d%d%d", &l, &r, &x, &y) != EOF) {
  31. ans = 0;
  32. if(y % x != 0) {
  33. printf("0\n");
  34. continue;
  35. }
  36. y /= x;
  37. l = (l + x - 1) / x;
  38. r /= x;
  39. for(int i = 1; i <= y / i; ++i) {
  40. if(y % i == 0) {
  41. int ii = y / i;
  42. if(i >= l && i <= r && ii >= l && ii <= r && gcd(i, ii) == 1) {
  43. ++ans;
  44. if(i != ii) {
  45. ++ans;
  46. }
  47. }
  48. }
  49. }
  50. printf("%d\n", ans);
  51. }
  52. return 0;
  53. }

C. Nastya and a Wardrobe

题意

最初一个衣柜中有 条裙子,每个月月末,衣柜里的裙子数就会翻倍,并且除了最后一个月以外,其他月的月末如果衣柜里有裙子的话都会有 的概率被偷一条裙子,问 个月后,衣柜里裙子数量的期望值。由于这个期望值总是整数,所以可以将答案对 取模后输出。

输入

两个整数

输出

输出对 取模后的答案。

样例

输入 输出
2 0 4
2 1 7
3 2 21

题解

先打出 时的表:

月份 0 1 2 3 4
翻倍










期望
被偷










可以发现,答案就是 ,由于 很大,所有要用个快速幂。最后要注意一下 的情况,由于对 翻倍仍然是 ,这时候没有裙子可以被偷,所以不满足上面的规律,应直接输出

过题代码

  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. typedef long long LL;
  20. const LL MOD = 1000000000 + 7;
  21. LL x, k;
  22. LL fast_pow(LL res, LL n) {
  23. LL ans = 1;
  24. for(ans = 1; n != 0; n >>= 1) {
  25. if(n % 2 == 1) {
  26. ans = (ans * res) % MOD;
  27. }
  28. res = (res * res) % MOD;
  29. }
  30. return ans;
  31. }
  32. int main() {
  33. #ifdef Dmaxiya
  34. freopen("test.txt", "r", stdin);
  35. // freopen("test1.out", "w", stdout);
  36. #endif // Dmaxiya
  37. ios::sync_with_stdio(false);
  38. while(scanf("%I64d%I64d", &x, &k) != EOF) {
  39. if(x == 0) {
  40. printf("0\n");
  41. continue;
  42. }
  43. x %= MOD;
  44. LL ans = fast_pow(2, k + 1);
  45. ans = (ans * x) % MOD;
  46. LL tmp = fast_pow(2, k);
  47. tmp = ((tmp - 1) % MOD + MOD) % MOD;
  48. ans -= tmp;
  49. ans = (ans % MOD + MOD) % MOD;
  50. printf("%I64d\n", ans);
  51. }
  52. return 0;
  53. }

D. Nastya and a Game

题意

给一个长度为 的序列,要求找到满足 的子段个数,其中 为被选中子段的数字乘积, 为被选中子段的数字和。

输入

第一行包含两个整数 。第二行为 个整数

输出

输出满足条件的子段数量。

样例

输入 输出
1 1
1
1
4 2
6 3 8 1
2

题解

由于 的最大值为 ,所以满足条件的子段内,不等于 的数字个数不会超过 ,因此只要关注不等于 的数字即可,通过枚举起点,当 时跳出枚举终点的循环,时间复杂度可以达到
我们可以知道,当 时,答案可以 ;当 时,需要一个非 的数字加入这个子段,才能使 增大,而更多的 反而使得 增大,不利于寻找答案,所以这时候应直接跳到下一个非 的位置;当 时,更多的 将会使 增大,这时候可以直接计算出所需要的 的数量:,解得 ,如果后面有连续的 ,则可以直接跳到这个位置,否则直接跳到下一个非 数字。最后注意一下乘法容易爆 ,应该用除法做比较。

过题代码

  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. typedef long long LL;
  20. const int maxn = 200000 + 100;
  21. int n, Index;
  22. LL ans;
  23. LL k, sum, num[maxn];
  24. int Next[maxn];
  25. int main() {
  26. #ifdef Dmaxiya
  27. freopen("test.txt", "r", stdin);
  28. // freopen("test1.out", "w", stdout);
  29. #endif // Dmaxiya
  30. ios::sync_with_stdio(false);
  31. while(scanf("%d%I64d", &n, &k) != EOF) {
  32. sum = 0;
  33. ans = 0;
  34. for(int i = 1; i <= n; ++i) {
  35. scanf("%I64d", &num[i]);
  36. sum += num[i];
  37. }
  38. Index = n + 1;
  39. for(int i = n; i > 0; --i) {
  40. Next[i] = Index;
  41. if(num[i] != 1) {
  42. Index = i;
  43. }
  44. }
  45. for(int i = 1; i <= n; ++i) {
  46. LL p, s;
  47. p = 1;
  48. s = 0;
  49. for(int j = i; j <= n; ++j) {
  50. if(!(p <= sum * k / num[j])) {
  51. break;
  52. }
  53. p *= num[j];
  54. s += num[j];
  55. if(p == s * k) {
  56. ++ans;
  57. continue;
  58. }
  59. int jj = Next[j] - 1;
  60. if(p < s * k) {
  61. if(jj != j) {
  62. s += jj - j;
  63. j = jj;
  64. }
  65. continue;
  66. }
  67. LL x = (p - k * s + k - 1) / k;
  68. if(j + x > jj) {
  69. x = jj - j;
  70. }
  71. s += x;
  72. j += x;
  73. if(p == k * s) {
  74. ++ans;
  75. }
  76. }
  77. }
  78. printf("%I64d\n", ans);
  79. }
  80. return 0;
  81. }

E. Nastya and King-Shamans

题意

给定一个长度为 的序列 ,记 ,有 次操作,每次操作将 改为 ,问每次操作之后,哪个位置上的数字满足

输入

第一行为两个整数 ,第二行为 个整数 ,接下去有 行,每行两个整数 ,表示执行操作

输出

输出 行,第 行表示进行第 次操作之后,满足 ,如果有多个解,则输出任意一个,如果不存在解,则输出

样例

输入 输出
2 1
1 3
1 2
-1
3 4
2 2 3
1 1
1 2
2 4
3 6
3
2
-1
3
10 7
0 3 1 4 6 2 7 8 10 1
2 5
1 3
9 36
4 10
4 9
1 2
1 0
1
-1
9
-1
4
-1
1

题解

我们定义一个新的数组 ,于是相当于要在 数组中查找满足条件 的位置,对于这个数组,如果进行操作 ,对于第 个数字,相当于 ,而这个数字的改变,也会使得在位置 之后的前缀和发生改变,相当于 ,而对于 数组,相当于执行了


这种修改正是区间加减,于是可以用线段树对这种修改进行维护,要找到 数组中为 的数组,我们可以维护区间最大值,因为对于 这样一个数组,其中大于 的数字个数是很少的,假设 数组中每个数字都大于 ,在最坏情况下( 数组长度最长), 数组中的元素应该为 最大为 ,因此 数组中最多只有 个数字大于 ,通过维护区间最大值的方法找 ,每次查找时间复杂度为 ,而查找出错(找到比 大的数字)的次数最大为 ,因此总的时间复杂度为

过题代码

  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. typedef long long LL;
  20. const int maxn = 200000 + 100;
  21. int n, q, p;
  22. LL x;
  23. LL num[maxn], sum[maxn];
  24. LL Max[maxn << 2], lazy[maxn << 2];
  25. void push_up(int rt) {
  26. Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]);
  27. }
  28. void push_down(int rt) {
  29. if(lazy[rt] != 0) {
  30. Max[rt << 1] += lazy[rt];
  31. Max[rt << 1 | 1] += lazy[rt];
  32. lazy[rt << 1 | 1] += lazy[rt];
  33. lazy[rt << 1] += lazy[rt];
  34. lazy[rt] = 0;
  35. }
  36. }
  37. void build(int l, int r, int rt) {
  38. lazy[rt] = 0;
  39. if(l == r) {
  40. Max[rt] = num[l] - sum[l - 1];
  41. return ;
  42. }
  43. int m = (l + r) >> 1;
  44. build(l, m, rt << 1);
  45. build(m + 1, r, rt << 1 | 1);
  46. push_up(rt);
  47. }
  48. void update(int L, int R, LL x, int l, int r, int rt) {
  49. if(L <= l && r <= R) {
  50. lazy[rt] += x;
  51. Max[rt] += x;
  52. return ;
  53. }
  54. push_down(rt);
  55. int m = (l + r) >> 1;
  56. if(L <= m) {
  57. update(L, R, x, l, m, rt << 1);
  58. }
  59. if(m < R) {
  60. update(L, R, x, m + 1, r, rt << 1 | 1);
  61. }
  62. push_up(rt);
  63. }
  64. int query(int l, int r, int rt) {
  65. if(l == r) {
  66. if(Max[rt] == 0) {
  67. return l;
  68. }
  69. return -1;
  70. }
  71. push_down(rt);
  72. int m = (l + r) >> 1;
  73. int ret = -1;
  74. if(Max[rt << 1] >= 0) {
  75. ret = max(ret, query(l, m, rt << 1));
  76. }
  77. if(ret != -1) {
  78. return ret;
  79. }
  80. if(Max[rt << 1 | 1] >= 0) {
  81. ret = max(ret, query(m + 1, r, rt << 1 | 1));
  82. }
  83. return ret;
  84. }
  85. int main() {
  86. #ifdef Dmaxiya
  87. freopen("test.txt", "r", stdin);
  88. // freopen("test1.out", "w", stdout);
  89. #endif // Dmaxiya
  90. ios::sync_with_stdio(false);
  91. while(scanf("%d%d", &n, &q) != EOF) {
  92. sum[0] = 0;
  93. for(int i = 1; i <= n; ++i) {
  94. scanf("%I64d", &num[i]);
  95. sum[i] = sum[i - 1] + num[i];
  96. }
  97. build(1, n, 1);
  98. while(q--) {
  99. scanf("%d%I64d", &p, &x);
  100. LL d = x - num[p];
  101. num[p] = x;
  102. update(p, p, d, 1, n, 1);
  103. if(p != n) {
  104. update(p + 1, n, -d, 1, n, 1);
  105. }
  106. printf("%d\n", query(1, n, 1));
  107. }
  108. }
  109. return 0;
  110. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注