Codeforces Round #636 (Div. 3)
Posted likunhong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #636 (Div. 3)相关的知识,希望对你有一定的参考价值。
A - Candies
题目大意:找到一个x ,存在k>1,使x + 2x + 4x + ? + 2^(k−1)x = n。
即找到x,k满足这个式子:(2^k-1)*x = n,可以枚举k 判断(2^k-1)|n
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for (register int i = a; i <= b; i++) int main() { int t; cin >> t; ll n; while (t--) { cin >> n; for (ll k = 2; (1 << k) - 1 <= n; k++) if (n % ((1 << k) - 1) == 0) { cout << n / ((1 << k) - 1) << endl; break; } } }
B. Balanced Array
题目大意,给一个偶数n,构造数列a满足:
1.前n/2个数为偶数
2.后n/2个数为奇数
3.所有数不相同,大于零
4.前n/2个数的和等于后n/2个数
因为左右部分的和相同,奇数部分的个数为偶数,因为和为偶数,所以n%4!=0则不可构造,
当n%4==0时,按照 2, 4, …, n-2, n, 1, 3, …, n-3, n+1, n+3, …, n+1 奇数中间跳一个值
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for (register int i = a; i <= b; i++) int main() { int t, n; cin >> t; while (t--) { cin >> n; if (n % 4) puts("NO"); else { puts("YES"); for (int i = 2; i <= n; i += 2) cout << i << " "; for (int i = 1; i <= n + 1; i += 2) if (i != n / 2 + 1) cout << i << " "; cout << endl; } } }
C. Alternating Subsequence
题目大意,给一个序列a,最大化长度最大的正负数交错排列的序列的和。
长度最大即连续的正数或负数之中必须要选一个,那么直接选最大的那个
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for (register int i = a; i <= b; i++) int main() { int t, n; ll ans, a, tmp; cin >> t; while (t--) { cin >> n; ans = 0; tmp = 0; rep(i, 1, n) { cin >> a; if (tmp * a > 0) tmp = max(tmp, a); else { ans += tmp; tmp = a; } } cout << ans + tmp << endl; } }
D. Constant Palindrome Sum
题目大意,给一个长度为n的序列a,将a中的值改为中[1,k]任意一个数,满足i∈[1,n/2] ai+an-i+1 = x值相等,求最小的修改次数。
可以发现对于每一对数,修改次数为0,1,2,由x决定
[ 2, min(a[i], a[n-i+1]) ] 2次
[ min(a[i], a[n-i+1])+1, a[i]+a[n-i+1]-1 ] 1次
a[i]+a[n-i+1] 0次
[ a[i]+a[n-i+1]+1,max(a[i], a[n-i+1])+k ] 1次
[ max(a[i], a[n-i+1])+k+1, 2*k ] 2次
枚举x∈[2,k * 2],遍历a数组,求得最小的修改次数,复杂度O(nk),显然不行
因为修改次数区间是连续的,可以用线段树或者树状数组来维护x∈[2,k * 2]的修改次数
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for (register int i = a; i <= b; i++) int n, k, ans, a[200010]; int c[400010]; int lowbit(int x) { return x & (-x); } void update(int x, int d) { while (x <= 2 * k + 1) { c[x] += d; x += lowbit(x); } } int getsum(int x) { int tmp = 0; while (x) { tmp += c[x]; x -= lowbit(x); } return tmp; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t; cin >> t; while (t--) { cin >> n >> k; rep(i, 1, n) cin >> a[i]; rep(i, 1, k * 2 + 1) c[i] = 0; rep(i, 1, n / 2) { update(2, 2); update(min(a[i], a[n - i + 1]) + 1, -1); update(a[i] + a[n - i + 1], -1); update(a[i] + a[n - i + 1] + 1, 1); update(max(a[i], a[n - i + 1]) + k + 1, 1); update(2 * k + 1, -2); } ans = n; rep(i, 2, 2 * k) ans = min(ans, getsum(i)); cout << ans << endl; } }
E. Weights Distributing
题目大意,给定无向无权图,给图加权值,使a->b,b->c代价最小
设a->b经过x,如果b->c经过x,那么一定是延a->x->b的方向返回至x,就可以理解成a->x->b->x->c
枚举x,求dis(a,x) + 2*dis(b,x) + dis(c,x)最小值,中间求个前缀和就行了
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for (register int i = a; i <= b; i++) int n, m, a, b, c; ll p[200010], ans; struct node { int to, next; } e[400010]; int id = 0, head[200010]; int disa[200010], disb[200010], disc[200010]; void add(int x, int y) { id++; e[id].to = y; e[id].next = head[x]; head[x] = id; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t, u, v; cin >> t; while (t--) { id = 0; memset(head, 0, sizeof(head)); cin >> n >> m >> a >> b >> c; rep(i, 1, m) cin >> p[i]; sort(p + 1, p + m + 1); rep(i, 1, m) p[i] += p[i - 1]; rep(i, 1, m) { cin >> u >> v; add(u, v); add(v, u); } rep(i, 1, n) disa[i] = disb[i] = disc[i] = -1; queue<int> q; q.push(a); disa[a] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = e[i].next) if (disa[e[i].to] == -1) { disa[e[i].to] = disa[u] + 1; q.push(e[i].to); } } q.push(b); disb[b] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = e[i].next) if (disb[e[i].to] == -1) { disb[e[i].to] = disb[u] + 1; q.push(e[i].to); } } q.push(c); disc[c] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = e[i].next) if (disc[e[i].to] == -1) { disc[e[i].to] = disc[u] + 1; q.push(e[i].to); } } ans = p[m] * 2; rep(i, 1, n) if (disa[i] + disb[i] + disc[i] <= m) ans = min(ans, p[disb[i]] + p[disa[i] + disb[i] + disc[i]]); cout << ans << endl; } }
以上是关于Codeforces Round #636 (Div. 3)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #636 (Div. 3)
Codeforces Round #636 (Div. 3)题解
codeforces Round #636 D. Constant Palindrome Sum
Codeforces Round #636 (Div. 3) E—Weights Distributing