Educational Codeforces Round 126 (Rated for Div. 2) A-D
Educational Codeforces Round 126 (Rated for Div. 2)
https://codeforces.com/contest/1661
昨天VP的一场
A Array Balancing
题意
给定两个长度相等的序列a和b,可以交换同一位置上的ai和bi,该操作能进行任意次。问最小的
\[\sum_{i=1}^{n-1}(|a_i-a_{i+1}|+|b_i-b_{i+1}|)
\]
是多少
思路
每次都比较两边的差值,然后交换就行(看代码)
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int main () {
int t; cin >> t;
while (t --) {
int n, a[N], b[N];
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= n; i ++)
cin >> b[i];
long long ans = 0;
// for (int i = n; i >= 2; i --) {
// if (abs (a[i] - a[i - 1]) == abs (b[i] - b[i - 1]))
// continue;
// swap (a[i], b[i]);
// }
for (int i = 2; i <= n; i ++) {
int d1 = abs (a[i] - a[i - 1]) + abs (b[i - 1] - b[i]);
int d2 = abs (b[i] - a[i - 1]) + abs (b[i - 1] - a[i]);
if (d1 > d2)
swap (a[i], b[i]);
ans += abs(a[i] - a[i - 1]) + abs (b[i] - b[i - 1]);
}
cout << ans << endl;
}
}
//我是猪
B Getting Zero
题意
给定n个数字v,可以进行如下两种操作任意次:
- v=(v+1) % 32768
- v=(v*2) % 32768
求最小操作次数,使得v=0
思路
我是直接BFS做的(但是不知道为什么大佬们好像不是这么做的hhh)
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 32768;
int dis[N + 5];
queue <int> q;
void change (int u, int v) {
if (dis[v] == 0x3f3f3f3f)
dis[v] = dis[u] + 1, q.push (v);
}
int main () {
int n, a[N + 5];
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= n; i ++) {
memset (dis, 0x3f3f3f3f, sizeof dis);
while (!q.empty())
q.pop();
int x = a[i];
//cin >> x;
if (x == 0) {
cout << 0 << endl;
continue;
}
dis[x] = 0;
q.push (x);
while (!q.empty()) {
int t = q.front();
q.pop();
if (t == 0) {
cout << dis[t] << ' ';
break;
}
change (t, (t + 1) % N);
change (t, (t * 2) % N);
}
}
}
C Water the Trees
题意
有n棵树,在奇数天可以使其增长1,在偶数天可以使其增长2,求使得n棵树高度相等所需要的最小天数
思路
要长高的高度为奇数的树至少需要一次在奇数天浇水,而要长高的高度为偶数的树无所谓
出现cnt1次奇数天最少需要2*cnt-1天
取maxn+1是因为有可能可以通过减少奇数天数的数量来降低答案,所以两个高度分别计算取小即可。
把\(2*cnt-1\)和总天数进行比较即可
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
int n, h[N];
long long find (int maxn) {
long long sum = 0, cnt1 = 0;
for (int i = 1; i <= n; i ++) {
int d = maxn - h[i];
sum += d;
if (d % 2)
cnt1 ++;
}
long long res = 0;
if (sum % 3 == 0)
res = max (cnt1 * 2LL - 1, sum / 3 * 2);
else if (sum % 3 == 1)
res = max (cnt1 * 2LL - 1, sum / 3 * 2 + 1);
else
res = max (cnt1 * 2LL - 1, sum / 3 * 2 + 2);
return res;
}
int main () {
int t;
cin >> t;
while (t --) {
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> h[i];
sort (h + 1, h + n + 1);
if (h[1] == h[n]) {
cout << 0 << endl;
continue;
}
cout << min (find(h[n]), find(h[n] + 1)) << endl;
//取maxn+1是因为有可能可以通过减少奇数天数的数量来降低答案,所以两个高度分别计算取小即可.
}
}
//要长高的高度为奇数的树至少需要一次在奇数天浇水,而要长高的高度为偶数的树无所谓
//出现cnt1次奇数天最少需要2*cnt-1天
D Progressions Covering
题意
思路
线段树 + 差分
贪心(倒序做)
Code
//差分+线段树
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 5;
int n, k, a[N];
struct Node {
int l, r;
int sum, add;
}st[N << 2];
void pushup (int u) {
st[u].sum = st[u << 1].sum + st[u << 1 | 1].sum;
}
void pushdown (int u) {
auto &uu = st[u], &ll = st[u << 1], &rr = st[u << 1 | 1];
ll.add += uu.add, ll.sum += (ll.r - ll.l + 1) * uu.add;
rr.add += uu.add, rr.sum += (rr.r - rr.l + 1) * uu.add;
uu.add = 0;
}
void build (int u, int l, int r) {
if (l == r) {
st[u] = {l, r, a[r] - a[r - 1], 0};
return;
}
st[u] = {l, r, 0, 0};
int mid = l + r >> 1;
build (u << 1, l, mid);
build (u << 1 | 1, mid + 1, r);
pushup (u);
}
void modify (int u, int l, int r, int v) {
if (st[u].l >= l && st[u].r <= r) {
st[u].sum += (st[u].r - st[u].l + 1) * v;
st[u].add += v;
return ;
}
pushdown (u);
int mid = st[u].l + st[u].r >> 1;
if (l <= mid)
modify (u << 1, l, r, v);
if (r > mid)
modify (u << 1 | 1, l, r, v);
pushup (u);
}
int query (int u, int l, int r) {
if (st[u].l >= l && st[u].r <= r) {
return st[u].sum;
}
pushdown (u);
int mid = st[u].l + st[u].r >> 1;
int res = 0;
if (l <= mid)
res += query (u << 1, l, r);
if (r > mid)
res += query (u << 1 | 1, l, r);
return res;
}
signed main () {
cin >> n >> k;
for (int i = 1; i <= n; i ++)
cin >> a[i];
build (1, 1, n);
int cnt = 0;
//最后一个元素只能被一种数列减去
for (int i = n; i >= 1; i --) {
int x = query (1, 1, i); //区间查询
if (x <= 0)
continue; //符合要求
int L = max(1LL, i - k + 1);
int R = L + k - 1;
int d = i - L + 1; //该点一次可以减去多少
int add = ceil(1.0 * x / d);
cnt += add;
modify (L, R, i, -add);
}
cout << cnt << endl;
return 0;
}
//差分