@Dmaxiya
2018-08-17T02:22:15.000000Z
字数 8006
阅读 1229
Codeforces
Contests 链接:Educational Codeforces Round 32
过题数:5
排名:266/8563
给定一个长度为 的序列 ,定义极值点表示某个数字 严格大于或小于它左右两边的值,即 或者 ,第一个数字和最后一个数字一定不是极值点,统计序列中极值点的个数。
第一行为一个整数 ,第二行为 个整数 。
输出序列中极值点的个数。
| 输入 | 输出 |
|---|---|
| 3 1 2 3 |
0 |
| 4 1 5 2 5 |
2 |
按题意从 到 跑一遍统计即可。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 1000 + 100;int n;int num[maxn];int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {int cnt = 0;for(int i = 1; i <= n; ++i) {scanf("%d", &num[i]);}for(int i = 2; i < n; ++i) {if((num[i] > num[i - 1] && num[i] > num[i + 1]) || (num[i] < num[i - 1] && num[i] < num[i + 1])) {++cnt;}}printf("%d\n", cnt);}return 0;}
给机器人一个字符串指令,字符串中只包含 和 四种字符,分别表示上下左右四个方向,机器人的初始位置为 ,而完全正确地执行这些指令可能无法回到原点,问机器人要回到原点最多正确地执行了多少个指令。
第一行为一个整数 表示指令的长度,第二行为一个字符串 ,只包含 四种字符,表示机器人接收到的指令。
输出机器人最终要回到原点,最多正确地执行多少个指令。
| 输入 | 输出 |
|---|---|
| 4 LDUR |
4 |
| 5 RRRUU |
0 |
| 6 LLRRRR |
4 |
统计所有字符出现的次数,分别记为 ,结果就是 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 100 + 100;int n;char str[maxn];map<char, int> mp;int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {mp.clear();scanf("%s", str);for(int i = 0; i < n; ++i) {++mp[str[i]];}printf("%d\n", 2 * (min(mp['L'], mp['R']) + min(mp['U'], mp['D'])));}return 0;}
如果在给定的字符串中,对于任意一个长度不小于 的子串,都包含字符 ,那么这个字符串就是 字符主导的字符串,现在给定一个字符串 ,要求可能满足条件的最小的 值。
输入为一个只包含小写字符的字符串 。
输出可能满足条件的最小的 值。
| 输入 | 输出 |
|---|---|
| abacaba | 2 |
| zzzzz | 1 |
| abcde | 3 |
对于在字符串中出现的每一个字符,都求出它对应的 值,取最小的那个 就是答案,而对于每一个字符 ,求 值的方法就是将所有距离最近的两个 ,求出它们距离的最大值,最后再对字符串的首尾做一次处理即可。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 100000 + 100;char str[maxn];int num[30], last[maxn];int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);while(scanf("%s", str) != EOF) {int len = strlen(str);memset(num, 0, sizeof(num));memset(last, -1, sizeof(last));for(int i = 0; str[i]; ++i) {int w = str[i] - 'a';num[w] = max(num[w], i - last[w]);last[w] = i;}int ans = maxn;for(int i = 0; i < 26; ++i) {if(last[i] != -1) {num[i] = max(num[i], len - last[i]);ans = min(ans, num[i]);}}printf("%d\n", ans);}return 0;}
如果一个 的排列为 ,那么它至少有 个数字满足 ,问给定 和 ,有多少个这样的序列满足条件。
输入只包含两个整数 。
输出满足条件的序列的数量。
| 输入 | 输出 |
|---|---|
| 4 1 | 1 |
| 4 2 | 7 |
| 5 3 | 31 |
| 5 4 | 76 |
本题由于 非常小,所以可以对每一个 分类讨论穷举所有情况
- 当 时,有 个数字在原位,那么最后一个数字一定也在原位,所以只有一种情况;
- 当 时,有 个数字在原位,那么最后剩下的两个数字不在原位的情况只有一种,所有情况就是 ,在加上 的情况的方案数就是答案;
- 当 时,除了 的情况,当有 个数字在原位时,剩下 个数字都不在原位的情况只有 种,所以总共有 种情况;
- 当 时,除了 的情况,当有 个数字不在原位时,剩下 个数字不在原位的情况有 种,所以总共有 种情况。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 1000 + 100;int n, k;LL C[maxn][maxn];void Init() {C[0][0] = 1;for(int i = 1; i < maxn; ++i) {for(int j = 0; j <= i; ++j) {if(j == 0 || j == i) {C[i][j] = 1;} else {C[i][j] = C[i - 1][j - 1] + C[i - 1][j];}}}}int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);Init();while(scanf("%d%d", &n, &k) != EOF) {LL ans = 0;if(k >= 1) {ans += 1;}if(k >= 2) {ans += C[n][2];}if(k >= 3) {ans += C[n][3] * 2;}if(k >= 4) {ans += C[n][4] * 9;}printf("%I64d\n", ans);}return 0;}
给定一个长度为 的序列 ,从中选出 个数字,它们的下标分别为 ,要使得 的值最大,求这个最大值。
第一行为两个整数 和 ,第二行为 个整数 。
输出答案。
| 输入 | 输出 | 提示 |
|---|---|---|
| 4 4 5 2 4 1 |
3 | 可以选择第 和第 个数字,这两个数字对 取模的值为 。 |
| 3 20 199 41 299 |
19 | 可以选择第 个数字。 |
本题如果 枚举每个数字选或者不选的话,总的时间复杂度为 ,肯定要超时,但是可以将整个数组分成两部分进行 次枚举,再对这两部分进行贪心二分求和即可,这样总的时间复杂度可以降到 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 100;int n, m, ans;int num[maxn];set<int> st[2];set<int>::iterator it, itt;void get_st(int begin, int end, set<int> &st) {st.clear();st.insert(0);for(int i = 0; i < (1 << (end - begin)); ++i) {int tmp = 0;for(int j = 0; j < end - begin; ++j) {if(((i >> j) & 1) == 1) {tmp = (tmp + num[j + begin]) % m;}}st.insert(tmp);}}int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);while(scanf("%d%d", &n, &m) != EOF) {ans = 0;for(int i = 0; i < n; ++i) {scanf("%d", &num[i]);}get_st(0, (n + 1) / 2, st[0]);get_st((n + 1) / 2, n, st[1]);for(it = st[0].begin(); it != st[0].end(); ++it) {for(int i = 1; i <= 2; ++i) {itt = st[1].lower_bound(m * i - *it);if(itt != st[1].begin()) {--itt;ans = max(ans, (*it + *itt) % m);}}}printf("%d\n", ans);}return 0;}
给定一个 个节点的完全图,每个节点的权值为 ,任意两个节点之间的边权值为 ,求最小生成树的边权和。
第一行为一个正整数 ,第二行为 个整数 。
输出最小生成树的边权和。
| 输入 | 输出 |
|---|---|
| 5 1 2 3 4 5 |
8 |
| 4 1 2 3 4 |
8 |
由贪心可以知道,高 位都相同的所有数字一定先合并到同一个连通块内,再和高 位相同的数字进行合并,这样得到的异或的和才能最小,因此问题转化为求解在高 位都相同,而第 位不同的情况下,两个子连通块的合并,合并的方式为:对于第 位为 的连通块内的所有数字,查找第 位为 的连通块内的所有数字的异或值最小的那一对数字,暴力是 的,可以用字典树将查找优化到 ,解决了两个连通块之间的连边代价计算之后,再加上两个连通块各自的子连通块(第 位不同的情况)连通的代价,一直递归下去,直到某个连通块不再存在元素或者到达第 位停止递归,总的时间复杂度为 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cfloat>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <ctime>#include <functional>#include <iomanip>using namespace std;#define LL long longconst int maxn = 200000 + 100;const int maxcnt = 200000 * 30 + 100;struct Tree {int root, cnt;int tree[maxcnt][2];int create() {++cnt;memset(tree[cnt], 0, sizeof(tree[cnt]));return cnt;}void Init() {cnt = 0;root = create();}int id(int x, int Index) {return ((x >> Index) & 1);}void add(int x) {int pos = root;for(int i = 30; i >= 0; --i) {int w = id(x, i);if(tree[pos][w] == 0) {tree[pos][w] = create();}pos = tree[pos][w];}}int query(int x) {int ret = 0;int pos = root;for(int i = 30; i >= 0; --i) {int w = id(x, i);if(tree[pos][w] == 0) {w = !w;ret |= (1 << i);}pos = tree[pos][w];}return ret;}};int n;int num[maxn];Tree t;LL dfs(int L, int R, int depth) {if(L + 1 >= R || depth == -1) {return 0;}LL ret = 0;int M = R;for(int i = L; i < R; ++i) {if(((num[i] >> depth) & 1) == 1) {M = i;break;}}ret += dfs(L, M, depth - 1) + dfs(M, R, depth - 1);if(M != L && R != M) {t.Init();for(int i = M; i < R; ++i) {t.add(num[i]);}int tmp = INT_MAX;for(int i = L; i < M; ++i) {tmp = min(tmp, t.query(num[i]));}ret += tmp;}return ret;}int main() {#ifdef LOCALfreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endifios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {for(int i = 1; i <= n; ++i) {scanf("%d", &num[i]);}sort(num + 1, num + 1 + n);printf("%I64d\n", dfs(1, n + 1, 30));}return 0;}