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,可以进行如下两种操作任意次:

  1. v=(v+1) % 32768
  2. 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;
}
//差分
posted @ 2022-04-30 08:02  Sakana~  阅读(24)  评论(0编辑  收藏  举报