@Dmaxiya
2019-01-16T08:47:11.000000Z
字数 7550
阅读 1369
Codeforces
Contests 链接:Educational Codeforces Round 58
过题数:4
排名:985/6146
输出不在范围 内的最小的正整数 ,要求 是 的整数倍。
第一行为一个整数 ,接下去有 行,第 行的三个整数分别为 。
对于每一行询问,输出对应的答案。
| 输入 |
|---|
| 5 2 4 2 5 10 4 3 10 1 1 2 3 4 6 5 |
| 输出 |
| 6 4 1 3 10 |
若 在 范围内,则输出 ,否则输出 。
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <cfloat>#include <climits>#include <iostream>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <algorithm>#include <bitset>#include <sstream>using namespace std;#define LL long longint T;int l, r, x;int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {scanf("%d%d%d", &l, &r, &x);if(x >= l && x <= r) {printf("%d\n", r / x * x + x);} else {printf("%d\n", x);}}return 0;}
用一个字符串来表示一个手风琴,其必须要满足的格式为:由
[开头,接着是一个:,往后是连续的多个或零个|,接着是一个:和]。给定一个字符串,问能否通过删除一些字符,使得最终剩下的字符串可以表示成一个手风琴,若能,求最长剩余字符串长度。
输入仅包含一个字符串 ,其中只包含小写字母以及
[、]、:、|这几种符号。
如果无法满足题意,则输出 ,否则输出能表示成手风琴的最长的字符串。
| 输入 |
|---|
|[a:b:|] |
| 输出 |
| 4 |
| 输入 |
|---|
|]:[|:] |
| 输出 |
| -1 |
先找出最左边的
[下标 以及最右边的]的下标 ,要求 ,接着找在[l,r]范围内最左边的:以及最右边的:,最后将这两个冒号间所有的|个数统计出来,答案就是|的个数 。
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <cfloat>#include <climits>#include <iostream>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <algorithm>#include <bitset>#include <sstream>using namespace std;#define LL long longconst int maxn = 500000 + 100;int len;char str[maxn];int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%s", str + 1) != EOF) {len = strlen(str + 1);int l = -1;int r = -1;for(int i = 1; i <= len; ++i) {if(str[i] == '[') {l = i;break;}}for(int i = len; i >= 1; --i) {if(str[i] == ']') {r = i;break;}}if(l == -1 || r == -1 || r <= l) {printf("-1\n");continue;}int ll = -1;int rr = -1;for(int i = l + 1; i < r; ++i) {if(str[i] == ':') {if(ll == -1) {ll = i;}rr = i;}}if(ll == -1 || rr == -1 || ll >= rr) {printf("-1\n");continue;}int ans = 4;for(int i = ll + 1; i < rr; ++i) {if(str[i] == '|') {++ans;}}printf("%d\n", ans);}return 0;}
给定 条线段,第 条线段的两个端点分别为 ,将这 条线段分别放入两个非空集合中,要求从这两个集合中分别任意取一条线段出来,这两条线段没有任何公共部分。
第一行为一个整数 ,接下去有 组数据,每组数据第一行为一个整数 ,数据保证所有数据的 的总和不超过 ,接下去 行每行两个整数 。
对于每组数据输出一行,若某组数据无解,则输出 ,否则输出 个整数 , 表示第 条线段被分到第 个集合中, 表示第 条线段被分到第 个集合中,若有多解则输出任意一个。
| 输入 |
|---|
| 3 2 5 5 2 3 3 3 5 2 3 2 3 3 3 3 4 4 5 5 |
| 输出 |
| 2 1 -1 1 1 2 |
| 提示 |
| 在第一组数据中,两条线段应被放到不同的集合中,但答案并不一定必须是 2 1,也可以是 1 2。 在第二组数据中,第三条线段与前两条线段相交,因此它们应该被分在同一个集合中,这样另一个集合就会为空,不满足题意,因此答案为 。 在第三组数据中,我们可以以任意方式将三条线段分配到两个不同的集合中,只要这两个集合非空就是合法的,因此总共有 种合法的答案。 |
将每条线段的两个端点拆开,左区间 标为 ,右区间 标为 ,以端点大小为主关键字从小到大、以下标为此关键词从小到大排序,最后对整个数组扫一遍,遇到左端点则放入集合中,遇到右端点则从集合中删除,最后用并查集维护相互覆盖的线段,只要存在至少两个连通块,就存在答案,将其中一个连通块中的线段放到集合 中,其他的连通块放入集合 中。
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <cfloat>#include <climits>#include <iostream>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <algorithm>#include <bitset>#include <sstream>using namespace std;#define LL long longconst int maxn = 100000 + 100;struct Node {int Index, x;};bool operator<(const Node &a, const Node &b) {return a.x == b.x? a.Index < b.Index: a.x < b.x;}int T, n, l, r;Node node[maxn << 1];set<int> st;int fa[maxn], ans[maxn];void Init() {for(int i = 1; i <= n; ++i) {fa[i] = i;}}int Find(int x) {return x == fa[x]? x: fa[x] = Find(fa[x]);}void unit(int x, int y) {int xx = Find(x);int yy = Find(y);fa[xx] = yy;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {scanf("%d", &n);st.clear();Init();for(int i = 1; i <= n; ++i) {scanf("%d%d", &l, &r);node[i].Index = i;node[i].x = l;node[i + n].Index = -i;node[i + n].x = r + 1;}sort(node + 1, node + 1 + 2 * n);for(int i = 1; i <= 2 * n; ) {while(i <= 2 * n && node[i].Index < 0) {st.erase(-node[i].Index);++i;}if(i == 2 * n + 1) {break;}int f;if(st.empty()) {f = node[i].Index;} else {f = *st.begin();}while(i <= 2 * n && node[i].Index > 0) {st.insert(node[i].Index);unit(node[i].Index, f);++i;}}bool flag = false;int f = Find(1);for(int i = 1; i <= n; ++i) {if(Find(i) == f) {ans[i] = 1;} else {flag = true;ans[i] = 2;}}if(!flag) {printf("-1\n");continue;}for(int i = 1; i <= n; ++i) {if(i != 1) {printf(" ");}printf("%d", ans[i]);}printf("\n");}return 0;}
给定一棵 个节点的树,树上的每个点都有一个权值 ,定义 表示从节点 到节点 的路径上所有节点(包括 两点)权值的 ,定义 表示从节点 到节点 的路径上所有节点的数量,对于任意一个节点有 。求在 的 对中, 的最大值。
第一行为一个整数 ,第二行为 个整数 ,接下去 行每行两个整数 ,表示节点 与节点 之间有一条连边,数据保证所有的边可以构成一棵树。
如果不存在满足条件的答案,输出 ,否则输出满足条件的 的最大值。
| 输入 |
|---|
| 3 2 3 4 1 2 2 3 |
| 输出 |
| 1 |
| 输入 |
|---|
| 3 2 3 4 1 3 2 3 |
| 输出 |
| 2 |
| 输入 |
|---|
| 3 1 1 1 1 2 2 3 |
| 输出 |
| 0 |
定义 表示以第 个节点为根,从其任意一个子节点往下的一条链,这条链上所有节点权值的 为 的倍数的最长长度,则可以得到 递推式:
其中 为节点 的所有子节点, 为 的所有质因子,答案为:
其中 表示序列中的次大值。
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <cfloat>#include <climits>#include <iostream>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <algorithm>#include <bitset>#include <sstream>using namespace std;#define LL long longconst int maxn = 200000 + 100;int n, ans, u, v;int num[maxn];vector<int> G[maxn];vector<int> fac[maxn];map<int, int> dp[maxn];map<int, int>::iterator it;int cnt;int prime[maxn];bool vis[maxn];void Prime(int n) {for(int i = 2; i <= n; ++i) {if(!vis[i]) {prime[cnt++] = i;}for(int j = 0; j < cnt && i <= n / prime[j]; ++j) {int k = i * prime[j];vis[k] = true;if(i % prime[j] == 0) {break;}}}}void dfs(int f, int x) {int len = G[x].size();for(int i = 0; i < len; ++i) {int pos = G[x][i];if(pos == f) {continue;}dfs(x, pos);}len = fac[num[x]].size();for(int i = 0; i < len; ++i) {int ffac = fac[num[x]][i];int MMax = 0;int Max = 0;int llen = G[x].size();for(int j = 0; j < llen; ++j) {int pos = G[x][j];if(pos == f) {continue;}it = dp[pos].find(ffac);if(it == dp[pos].end()) {continue;}if(it->second >= Max) {MMax = Max;Max = it->second;} else if(it->second > MMax) {MMax = it->second;}}ans = max(ans, 1 + Max + MMax);dp[x][ffac] = 1 + Max;}}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);#endif // Dmaxiyaios::sync_with_stdio(false);Prime(maxn - 1);for(int i = 0; i < cnt; ++i) {for(int j = prime[i]; j < maxn; j += prime[i]) {fac[j].push_back(prime[i]);}}scanf("%d", &n);for(int i = 1; i <= n; ++i) {scanf("%d", &num[i]);}for(int i = 1; i < n; ++i) {scanf("%d%d", &u, &v);G[u].push_back(v);G[v].push_back(u);}dfs(1, 1);printf("%d\n", ans);return 0;}
给定两种操作:
- 从一个初始为空的集合中加入一张大小为 的票据;
- 询问大小为 的钱包是否能装下所有票据。
对于所有已经被加入集合的票据,满足以下任意一个条件,则钱包能够装下所有票据:
- 且 ;
- 且 。
对于每次询问,输出钱包是否能够装下集合中所有的票据。
第一行包含一个整数 ,接下去有 次操作,每次操作格式为以下两个之一:
- ,表示加入一张大小为 的票据;
- ,询问大小为 的钱包能否放下集合中的所有票据。
数据保证在第一个询问 之前至少存在一个询问 ,并且至少存在一个询问 。
对于每次询问,输出 或 ,表示答案。
| 输入 |
|---|
| 9 + 3 2 + 2 3 ? 1 20 ? 3 3 ? 2 3 + 1 5 ? 10 10 ? 1 5 + 1 1 |
| 输出 |
| NO YES YES YES NO |
对于每次放入的票据,每次取短边的最大值和长边的最大值,对于每次询问,只要短边的最大值小于等于钱包的短边,长边的最大值小于等于钱包的长边即可。
#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <cfloat>#include <climits>#include <iostream>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <algorithm>#include <bitset>#include <sstream>using namespace std;#define LL long longint n, l, r, maxl, maxr;char ch[2];int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);#endif // Dmaxiyaios::sync_with_stdio(false);while(scanf("%d", &n) != EOF) {maxl = 0;maxr = 0;for(int i = 0; i < n; ++i) {scanf("%s%d%d", ch, &l, &r);if(l > r) {swap(l, r);}if(ch[0] == '+') {maxl = max(maxl, l);maxr = max(maxr, r);} else {if(l >= maxl && r >= maxr) {printf("YES\n");} else {printf("NO\n");}}}}return 0;}