Educational Codeforces Round 37 所有题目整理!
2018-02-05 00:01
218 查看
A.Water The Garden
int ct = a / p; if (a % p != 0) ++ct; 等价于 ct = (a + p - 1) / p;
B. Tea Queue
solution:按照题意模拟即可C. Swap Adjacent Elements
题意:给定1-n的一个排列,存在一些i,其中1<=i < n,a[i]可以和a[i+1]交换, 询问是否可以通过一系列交换操作,使得序列升序。思路:首先考虑数字1,假设其位置为pos1,必然需要从pos1位置通过交换移到1位置,需要a[1]、a[2]….a[pos-1]均可交换;然后考虑数字2,假设初始位置pos2,可能由于之前数字1的移动,导致数字2在pos2的基础上右移,但是由于交换是可逆的,必然存在一种方式,可逆的从现位置移动到pos2位置,因此我们只需要考虑是否可以从pos2位置通过交换移动到2位置,需要a[2]…a[pos2-1]均可交换。
对于任意的数字k,只需要保证a[k]…..a[posk-1]均可交换即可
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f3f3f3f3f #define N 250037 #define pb push_back #define mp make_pair #define ff first #define ss second int n, m; int a , sum ; char s ; bool cal(int l, int r) { return sum[r] - sum[l - 1] == r - l + 1; } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", a + i); scanf("%s", s + 1); for(int i = 1; i < n; i++) { sum[i] = sum[i - 1]; if (s[i] == '1') sum[i]++; } bool res = true; for(int i = 1; i <= n; i++) { if (a[i] == i) continue; if (a[i] < i && !cal(a[i], i - 1)) res = false; if (a[i] > i && !cal(i, a[i] - 1)) res = false; } if (res) puts("YES"); else puts("NO"); return 0; }
D. Tanks
Solution由于勺子每次可以改变k的水量,因此我们首先考虑是否可以构造出m的水量,其中v≡m(mod k),我们可以通过朴素的01背包预处理出来O(nk),然后通过f数组倒推出对应的方案。
假设此方案需要t个tank,将这t个tank的水分都集中到一个tank上,其余n-t的tank水分集中到一个tank上,假设这两个坦克编号分别为now1和now2,其中a[now1]%k必定为m,a[now1]的水量与目标v只差若干个k。
如果a[now1]的水量多,直接将多的水量移到now2上就可以;如果他少的话,将a[now2]的水量移到a[now1]上,尽量移,不够移的则无解
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5010; int n, k, V; bool f ; int a , b ; int Cal(int x, int y) { int ct = a[x] / k; if (a[x] % k != 0) ++ct; a[y] += a[x]; a[x] = 0; return ct; } struct node { int cnt, x, y; } ans ; int cur = 0; int main(){ scanf("%d%d%d", &n, &k, &V); int sum = 0; for(int i = 1; i <= n; i++) scanf("%d", a + i), b[i] = a[i] % k, sum += a[i]; if (sum < V) { puts("NO"); return 0; } f[0][0] = true; for(int i = 0; i < n; i++) for(int j = 0; j < k; j++) if (f[i][j]) f[i + 1][j] = true, f[i + 1][(j + b[i + 1]) % k] = true; if (!f [V % k]) { puts("NO"); return 0; } vector<int> s; int res = V % k; for(int i = n; i >= 1; i--) { if (f[i-1][res]) continue; s.push_back(i); res -= b[i]; if (res < 0) res %= k, res += k; } int top = s.size(), now1, now2 = -1; if (top == 0) { ans[++cur] = (node) { Cal(1, 2), 1, 2}; now1 = 1; } else now1 = s[0]; for(int i = 1; i < top; i++) ans[++c 4000 ur] = (node){Cal(s[i], now1), s[i], now1}; for(int i = 1; i <= n; i++) if (i != now1 ) { now2 = i; break; } for(int i = 1; i <= n; i++) if (i != now1 && i != now2 && a[i]) ans[++cur] = (node){Cal(i, now2), i, now2}; if (a[now1] < V) { //printf("test %d %d %d %d\n", now1, now2, a[now1], a[now2]); int res = (V - a[now1]) / k; int tot = min(a[now2] / k, res); if (tot < res) { puts("NO"); return 0; } ans[++cur] = (node){tot, now2, now1}; a[now1] += tot * k; a[now2] -= tot * k; } else if (a[now1] > V) { // printf("test %d %d %d %d\n", now1, now2, a[now1], a[now2]); int res = (a[now1] - V) / k; ans[++cur] = (node){res, now1, now2}; } puts("YES"); for(int i = 1; i <= cur; i++) if (ans[i].cnt) printf("%d %d %d\n", ans[i].cnt, ans[i].x, ans[i].y); return 0; }
E Connected Components?
题意:给定无向图,求其补图的联通块数目及每个联通块的点数量思路:很nb的做法…..设原图边集为E,点集为V
初始我们任意拿出一个点x,遍历点集V,对于点y,若(x, y) 不属于E,则(x, y)存在于补图中,因此我们将y加入到此联通块中,及压入队列中,将一系列的y及x从V中删除;然后继续拿队列的其他节点遍历V,直至队列为空。此时相当于找到了一个联通块,队列中出现过的元素个数即为联通块点数量。
为了降低复杂度,我们用链表来维护点集,复杂度O(V+E)
首先每个点最多进队列一次,队列的每个元素遍历点集V可能会造成较高的复杂度,但是我们从另一个方向上去考虑,点集V的每个元素x最多会被枚举多少次? x被枚举多次是因为枚举完以后没有删除导致的,那什么时候枚举完x后,不会从链表中删除x呢? 当队列元素与x在原图联边时..x
不会被删除,因此x最大枚举次数就是原图中x的连边数
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 350010; int n, m; vector<int> adj ; struct node { int pre, nxt; } l ; bool vis , f ; vector<int> ans; void del(int x) { l[l[x].pre].nxt = l[x].nxt; l[l[x].nxt].pre = l[x].pre; } void bfs(int st) { queue<int> q; q.push(st); f[st] = true; int cnt = 0; while(!q.empty()) { int x = q.front(); cnt++; q.pop(); for(auto v : adj[x]) vis[v] = true; for(int i = l[0].nxt; i != 0; i = l[i].nxt) if (!vis[i] && !f[i]) q.push(i), del(i), f[i] = true; for(auto v : adj[x]) vis[v] = false; } ans.push_back(cnt); } int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); adj[x].push_back(y); adj[y].push_back(x); } for(int i = 1; i <= n; i++) l[i].pre = i - 1, l[i - 1].nxt = i; l .nxt = 0; for(int i = 1; i <= n; i++) if (!f[i]) bfs(i); sort(ans.begin(), ans.end()); printf("%d\n", ans.size()); printf("%d", ans[0]); for(int i = 1; i < ans.size(); i++) printf(" %d", ans[i]); return 0; }
F. SUM and REPLACE
思路:线段树的套路题,当一种操作在多次重复后不对序列产生影响时,用这种暴力打标记的方法就好。举个例子,对一个数字开根号,常数次以后就会变成数字一,那么之后的开根号操作就不会产生影响。这道题目我们可以对于线段树的每个节点i,打一个标记vis[i],代表这个节点对应的区间[l, r],replace 操作是否还会产生影响;对于每个replace 操作, 如果当前区间vis值为1,直接return掉就好,否则分层replace,当分到叶子层的时候,判断一下vis值,上调整的时候update vis值即可
#include <bits/stdc++.h> using namespace std; #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define ls x << 1 #define rs x << 1 | 1 typedef long long ll; const int N = 350010; struct node { ll sum; bool delta; } tree[N << 2]; int a , n, m; int d[1000007]; int ql, qr; void pushUp(int x) { tree[x].sum = tree[ls].sum + tree[rs].sum; tree[x].delta = tree[ls].delta & tree[rs].delta; } void build(int x, int l, int r) { if (l == r) { tree[x].sum = a[l]; tree[x].delta = (d[a[l]] == a[l]); return; } int mid = (l + r) >> 1; build(lson), build(rson); pushUp(x); } void update(int x, int l, int r) { node& e = tree[x]; if (ql <= l && qr >= r) { if (e.delta) return; if (l == r) { e.sum = d[e.sum]; e.delta = (d[e.sum] == e.sum); return; } } int mid = (l + r) >> 1; if (ql <= mid) update(lson); if (qr > mid) update(rson); pushUp(x); } ll query(int x, int l, int r) { if (ql <= l && qr >= r) return tree[x].sum; ll ans = 0; int mid = (l + r) >> 1; if (ql <= mid) ans += query(lson); if (qr > mid) ans += query(rson); return ans; } int main(){ for(int i = 1; i <= 1000000; i++) for(int j = i; j <= 1000000; j += i) d[j]++; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%d", a + i); build(1, 1, n); while(m--) { int t; scanf("%d%d%d", &t, &ql, &qr); if (t == 1) update(1, 1, n); else cout << query(1, 1, n) << endl; } return 0; }
G. List Of Integers
题目:考虑满足y>x,gcd(p, y) = 1条件下的第k小的y思路:通过gcd(p, y)=1 可以读到满满的容斥气息(可能因为我比较辣鸡…没有读到),我们二分答案y,然后利用容斥算出x,mid之间满足gcd(p, y)=1的数量,与k比较一下可以判断得到答案是大了还是小了;
注意一点,我们找的是num>=k对应的最小的y
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 350010; int n, m; ll cal(ll mid, vector<ll> f) { ll res = 0; int n = f.size(); for(int i = 0; i < (1 << n); i++) { ll tot = 1, k = 1; for(int j = 0; j < n; j++) if (i >> j & 1) tot *= f[j], k *= -1; res += k * (mid / tot); } // printf("%lld->%lld %d\n", mid, res, n); return res; } int main(){ int T; scanf("%d", &T); while(T--) { ll x, p, k; scanf("%lld%lld%lld", &x, &p, &k); vector<ll> f; int tot = sqrt(p); for(int i = 2; i <= tot; i++) if (p % i == 0){ f.push_back(i); while(p % i == 0) p /= i; } if (p > 1) f.push_back(p); ll sub = cal(x, f); ll l = x + 1, r = 1e12; ll ans = -1; while(l <= r) { ll mid = (l + r) >> 1; if (cal(mid, f) - sub >= k) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%lld\n", ans); } return 0; }
相关文章推荐
- Educational Codeforces Round 37 E. Connected Components?(bfs)
- Wannafly挑战赛9+Educational Codeforces Round 37 (Rated for Div. 2)
- Educational Codeforces Round 37 E. Connected Components?(920E)
- Educational Codeforces Round 37 (Rated for Div. 2)
- Educational Codeforces Round 37 [Codeforces920]
- 【Educational Codeforces Round 37 F】SUM and REPLACE
- Educational Codeforces Round 37
- Educational Codeforces Round 37 (Rated for Div. 2) E. Congruence Equation
- Educational Codeforces Round 37 (Rated for Div. 2)【A B C】【水】【模拟】
- Educational Codeforces Round 37 (Rated for Div. 2)-E-Connected Components?(模拟/暴力)
- Educational Codeforces Round 37 E. Connected Components?(bfs+思路)
- Educational Codeforces Round 37 (Rated for Div. 2) 920E E. Connected Components?
- codeforces 920 EFG 题解合集 ( Educational Codeforces Round 37 )
- Educational Codeforces Round 37 (Rated for Div. 2)-F-SUM and REPLACE(线段树)
- Educational Codeforces Round 37 (Rated for Div. 2) C. Swap Adjacent Elements
- 【CodeForces】Educational Codeforces Round 37 题解
- 【Educational Codeforces Round 6B】【暴力】Grandfather Dovlet’s calculator 区间所有数的火柴总成本
- 【Educational Codeforces Round 37 A】 Water The Garden
- Educational Codeforces Round 37 (Rated for Div. 2)
- 【Educational Codeforces Round 37 B】 Tea Queue