@Dmaxiya
2018-08-17T02:26:23.000000Z
字数 7824
阅读 1159
Codeforces
Contests 链接:Codeforces Round #489 (Div. 2)
过题数:3
排名:289/6253
有一个长度为 的序列,每一秒她可以将这个序列上的所有非零的数字加上同一个数字,如果这个序列所有的数字都等于 ,那么这个序列就爆炸了,问最少需要多少秒,能够使这个序列爆炸。
第一行包含一个整数 ,第二行包含 个整数 表示这个序列中的每一个数字。
一个整数,表示最少能够使这个序列爆炸的时间。
| 输入 | 输出 |
|---|---|
| 5 1 1 1 1 1 |
1 |
| 3 2 0 -1 |
2 |
| 4 5 -6 -5 1 |
4 |
直接判断序列中有多少个不同的非零数字。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>using namespace std;typedef long long LL;int n, x;set<int> st;int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("test1.out", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {st.clear();for(int i = 0; i < n; ++i) {scanf("%d", &x);if(x != 0) {st.insert(x);}}int ans = st.size();printf("%d\n", ans);}return 0;}
定义一对好的整数,这对整数必须满足 且 ,问在区间 内,有多少对好的整数。如果 ,则 与 被认为是不同的整数对。
输入包含四个整数 。
输出问题的答案。
| 输入 | 输出 |
|---|---|
| 1 2 1 2 | 2 |
| 1 12 1 12 | 4 |
| 50 100 3 30 | 0 |
要满足 且 ,首先必须满足 ,否则不存在满足要求的整数对。设 ,则 且 ,所以 ,因此问题就转化为求在区间 内的 的因子对 的个数,其中 , 地枚举即可。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>using namespace std;typedef long long LL;int l, r, x, y, ans;int gcd(int a, int b) {return b == 0? a: gcd(b, a % b);}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("test1.out", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%d%d%d%d", &l, &r, &x, &y) != EOF) {ans = 0;if(y % x != 0) {printf("0\n");continue;}y /= x;l = (l + x - 1) / x;r /= x;for(int i = 1; i <= y / i; ++i) {if(y % i == 0) {int ii = y / i;if(i >= l && i <= r && ii >= l && ii <= r && gcd(i, ii) == 1) {++ans;if(i != ii) {++ans;}}}}printf("%d\n", ans);}return 0;}
最初一个衣柜中有 条裙子,每个月月末,衣柜里的裙子数就会翻倍,并且除了最后一个月以外,其他月的月末如果衣柜里有裙子的话都会有 的概率被偷一条裙子,问 个月后,衣柜里裙子数量的期望值。由于这个期望值总是整数,所以可以将答案对 取模后输出。
两个整数 。
输出对 取模后的答案。
| 输入 | 输出 |
|---|---|
| 2 0 | 4 |
| 2 1 | 7 |
| 3 2 | 21 |
先打出 时的表:
月份 0 1 2 3 4 翻倍 期望 被偷 可以发现,答案就是 ,由于 很大,所有要用个快速幂。最后要注意一下 的情况,由于对 翻倍仍然是 ,这时候没有裙子可以被偷,所以不满足上面的规律,应直接输出 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>using namespace std;typedef long long LL;const LL MOD = 1000000000 + 7;LL x, k;LL fast_pow(LL res, LL n) {LL ans = 1;for(ans = 1; n != 0; n >>= 1) {if(n % 2 == 1) {ans = (ans * res) % MOD;}res = (res * res) % MOD;}return ans;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("test1.out", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%I64d%I64d", &x, &k) != EOF) {if(x == 0) {printf("0\n");continue;}x %= MOD;LL ans = fast_pow(2, k + 1);ans = (ans * x) % MOD;LL tmp = fast_pow(2, k);tmp = ((tmp - 1) % MOD + MOD) % MOD;ans -= tmp;ans = (ans % MOD + MOD) % MOD;printf("%I64d\n", ans);}return 0;}
给一个长度为 的序列,要求找到满足 的子段个数,其中 为被选中子段的数字乘积, 为被选中子段的数字和。
第一行包含两个整数 和 。第二行为 个整数 。
输出满足条件的子段数量。
| 输入 | 输出 |
|---|---|
| 1 1 1 |
1 |
| 4 2 6 3 8 1 |
2 |
由于 的最大值为 ,所以满足条件的子段内,不等于 的数字个数不会超过 个 ,因此只要关注不等于 的数字即可,通过枚举起点,当 时跳出枚举终点的循环,时间复杂度可以达到 。
我们可以知道,当 时,答案可以 ;当 时,需要一个非 的数字加入这个子段,才能使 增大,而更多的 反而使得 增大,不利于寻找答案,所以这时候应直接跳到下一个非 的位置;当 时,更多的 将会使 增大,这时候可以直接计算出所需要的 的数量:,解得 ,如果后面有连续的 个 ,则可以直接跳到这个位置,否则直接跳到下一个非 数字。最后注意一下乘法容易爆 ,应该用除法做比较。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>using namespace std;typedef long long LL;const int maxn = 200000 + 100;int n, Index;LL ans;LL k, sum, num[maxn];int Next[maxn];int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("test1.out", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%d%I64d", &n, &k) != EOF) {sum = 0;ans = 0;for(int i = 1; i <= n; ++i) {scanf("%I64d", &num[i]);sum += num[i];}Index = n + 1;for(int i = n; i > 0; --i) {Next[i] = Index;if(num[i] != 1) {Index = i;}}for(int i = 1; i <= n; ++i) {LL p, s;p = 1;s = 0;for(int j = i; j <= n; ++j) {if(!(p <= sum * k / num[j])) {break;}p *= num[j];s += num[j];if(p == s * k) {++ans;continue;}int jj = Next[j] - 1;if(p < s * k) {if(jj != j) {s += jj - j;j = jj;}continue;}LL x = (p - k * s + k - 1) / k;if(j + x > jj) {x = jj - j;}s += x;j += x;if(p == k * s) {++ans;}}}printf("%I64d\n", ans);}return 0;}
给定一个长度为 的序列 ,记 ,有 次操作,每次操作将 改为 ,问每次操作之后,哪个位置上的数字满足 。
第一行为两个整数 ,第二行为 个整数 ,接下去有 行,每行两个整数 ,表示执行操作 。
输出 行,第 行表示进行第 次操作之后,满足 的 ,如果有多个解,则输出任意一个,如果不存在解,则输出 。
| 输入 | 输出 |
|---|---|
| 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 |
我们定义一个新的数组 ,于是相当于要在 数组中查找满足条件 的位置,对于这个数组,如果进行操作 ,对于第 个数字,相当于 ,而这个数字的改变,也会使得在位置 之后的前缀和发生改变,相当于 ,而对于 数组,相当于执行了
这种修改正是区间加减,于是可以用线段树对这种修改进行维护,要找到 数组中为 的数组,我们可以维护区间最大值,因为对于 这样一个数组,其中大于 的数字个数是很少的,假设 数组中每个数字都大于 ,在最坏情况下( 数组长度最长), 数组中的元素应该为 , 最大为 ,因此 数组中最多只有 个数字大于 ,通过维护区间最大值的方法找 ,每次查找时间复杂度为 ,而查找出错(找到比 大的数字)的次数最大为 ,因此总的时间复杂度为 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <functional>#include <iomanip>using namespace std;typedef long long LL;const int maxn = 200000 + 100;int n, q, p;LL x;LL num[maxn], sum[maxn];LL Max[maxn << 2], lazy[maxn << 2];void push_up(int rt) {Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]);}void push_down(int rt) {if(lazy[rt] != 0) {Max[rt << 1] += lazy[rt];Max[rt << 1 | 1] += lazy[rt];lazy[rt << 1 | 1] += lazy[rt];lazy[rt << 1] += lazy[rt];lazy[rt] = 0;}}void build(int l, int r, int rt) {lazy[rt] = 0;if(l == r) {Max[rt] = num[l] - sum[l - 1];return ;}int m = (l + r) >> 1;build(l, m, rt << 1);build(m + 1, r, rt << 1 | 1);push_up(rt);}void update(int L, int R, LL x, int l, int r, int rt) {if(L <= l && r <= R) {lazy[rt] += x;Max[rt] += x;return ;}push_down(rt);int m = (l + r) >> 1;if(L <= m) {update(L, R, x, l, m, rt << 1);}if(m < R) {update(L, R, x, m + 1, r, rt << 1 | 1);}push_up(rt);}int query(int l, int r, int rt) {if(l == r) {if(Max[rt] == 0) {return l;}return -1;}push_down(rt);int m = (l + r) >> 1;int ret = -1;if(Max[rt << 1] >= 0) {ret = max(ret, query(l, m, rt << 1));}if(ret != -1) {return ret;}if(Max[rt << 1 | 1] >= 0) {ret = max(ret, query(m + 1, r, rt << 1 | 1));}return ret;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("test1.out", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%d%d", &n, &q) != EOF) {sum[0] = 0;for(int i = 1; i <= n; ++i) {scanf("%I64d", &num[i]);sum[i] = sum[i - 1] + num[i];}build(1, n, 1);while(q--) {scanf("%d%I64d", &p, &x);LL d = x - num[p];num[p] = x;update(p, p, d, 1, n, 1);if(p != n) {update(p + 1, n, -d, 1, n, 1);}printf("%d\n", query(1, n, 1));}}return 0;}