Codeforces Round 882 (Div. 2) A-E

发布时间 2023-07-15 16:56:59作者: FlyingLight

Codeforces Round 882 (Div. 2) A-E

题目链接:Codeforces Round 882 (Div. 2)

A. The Man who became a God

题意

定义一个区间的\(f(l,r)\)\(f(l,r)=|a_l-a_{l+1}|+|a_{l+1}-a_{l+2}|+...+|a_{r-1}-a_r|\),让求把\(n\)个数的序列分成\(k\)个连续子区间时,最大的\(f\)和。

思路

由于\(f(1,n)=|a_1-a_2|+|a_2-a_3|+...+|a_{n-1}-a_n|\),假如一个分割处的下标在\(x\)\(x+1\)之间,就相当于在总和里减去了\(|a_x-a_{x+1}|\),也就是说,\(k\)个连续子区间实际上就是减去\(k-1\)个绝对值。所以把所有绝对值排一下序,取前\((n-1)-(k-1)=n-k\)个就行。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e3 + 5;

int a[maxn];

void sol() {
    int n, k;
    cin >> n >> k;
    int tmp;
    cin >> tmp;
    for (int i = 1; i <= n - 1; ++i) {
        int x;
        cin >> x;
        a[i] = abs(tmp - x);
        tmp = x;
    }
    sort(a + 1, a + n);
    int ans = 0;
    for (int i = 1; i <= n - k; ++i) {
        ans += a[i];
    }
    cout << ans << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

B. Hamon Odyssey

题意

定义一个区间的\(f(l,r)\)\(f(l,r)=a_l\&a_{l+1}\&a_{l+2}\&...\&a_r\),让求分割连续子区间时,能够使让子区间的\(f\)值之和达到最小的最大的子区间个数。

思路

由于\(f_{min}=f(1,n)\),所以当\(f(1,n)≠0\)时答案只能为\(1\)。所以当\(f(1,n)=0\)时,贪心一遍就行。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int a[maxn];

void sol() {
    int n;
    cin >> n;
    int tmp;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        if (i == 1) tmp = a[i];
        tmp &= a[i];
    }
    if (tmp != 0) {
        cout << 1 << endl;
        return;
    }
    int t = a[1], ans = 0;
    for (int i = 1; i <= n; ++i) {
        t &= a[i];
        if (t == tmp) {
            ans += 1;
            t = a[i + 1];
        }
    }
    cout << ans << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

C. Vampiric Powers, anyone?

题意

设原数组为\(a[i]\)\(b[i] = max_{j=1}^{i}(a[j]\bigoplus a[j+1]\bigoplus a[j+1]\bigoplus...\bigoplus a[i])\),让求最大的\(b[i]\)

思路

这题很容易想到暴力,但是\(n\leq 1e5\),直接两重循环会爆时间,但是由于\(a[i]<2^8\)这里可以暴力所有异或的值,时间复杂度为\(O(2^8n)=2e7\)。当然,用Trie树也可做。

代码

#include <bits/stdc++.h>
using namespace std;
const int m = (1 << 8) - 1, maxn = 1e5 + 5;
bool vis[m + 1];
int a[maxn];

void sol() {
    int n, ans = -1;
    cin >> n;
    for (int i = 0; i <= m; ++i) vis[i] = false;
    vis[0] = true;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    int x = 0;
    for (int i = 1; i <= n; ++i) {
        x ^= a[i];
        for (int j = 0; j <= m; ++j) {
            if (vis[j]) ans = max(ans, j ^ x);
        }
        vis[x] = true;
    }
    cout << ans << endl;
}

int main() {
    int _;
    cin >> _;
    while (_--) sol();
    return 0;
}

D. Professor Higashikata

题意

\(s\)为一个只包含\('0'\)\('1'\)的字符串。定义\(t(s)=t_1+t_2+...+t_m\),其中\(t_i=s[l_i,r_i]\)。定义一次操作为交换任意两个\(s\)里的元素。定义每次更新为把\(s_{x_i}\)置反。

对于每次更新后的\(s\),要求输出至少需要操作多少次才能让\(t(s)\)的字典序最大。

思路

对于\(s\)\('1'\)应该存在于尽可能靠前的\(t_i\)中,且在\(t_i\)中的位置也应该尽可能靠前。对于一个元素\(s_i\),如果他存在于\(t_j\)中,那么他就不需要再放入\(t_k(k>j)\)当中了,因为\('1'\)是尽可能靠前放的,如果\(t_j\)中的\(s_i\)已置为\('1'\),那么\(t_k\)中的\(s_i\)也已经为\('1'\)了,不需要再考虑;而如果\('1'\)的数量少。不足以放到\(t_j\)中的\(s_i\),那么更不可能放到\(t_k\)当中。所以一个\(s_i\)要么在\(t(s)\)中有一个对映,要么没对应。

我们需要记录下标从\(s\)\(t(s)\)的对应关系,然后对\(t(s)\)建一个树状数组。这样的话,对于每次更新,维护\(s\)\('1'\)的个数,那么结果实际上就是\(min(t的长度, s中'1'的个数) - query(min(t的长度, s中'1'的个数))\)

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

char s[maxn], ss[maxn];
int a[maxn], g = 0, idx[maxn];
vector<int> v[maxn], vv[maxn];
set<int> se;

int tree[maxn];

int lowbit(int x) { return x & -x; }

void add(int x, int d) {
    while (x <= g) {
        tree[x] += d;
        x += lowbit(x);
    }
}

int query(int x) {
    int sum = 0;
    while (x > 0) {
        sum += tree[x];
        x -= lowbit(x);
    }
    return sum;
}

void sol() {
    int n, m, q, sum = 0;
    cin >> n >> m >> q;
    cin >> (s + 1);
    for (int i = 1; i <= n; ++i)
        if (s[i] == '1') sum += 1;
    for (int i = 1; i <= m; ++i) {
        int l, r;
        cin >> l >> r;
        v[l].push_back(i);
        v[r + 1].push_back(-i);
    }
    for (int i = 1; i <= n; ++i) {
        for (int x : v[i]) {
            if (x < 0)
                se.erase(se.lower_bound(-x));
            else
                se.insert(x);
        }
        if (se.empty())
            a[i] = 0;
        else
            a[i] = *se.begin(), vv[*se.begin()].push_back(i);
    }
    for (int i = 1; i <= m; ++i)
        for (int x : vv[i]) {
            ss[++g] = s[x];
            idx[x] = g;
        }
    for (int i = 1; i <= g; ++i)
        if (ss[i] == '1') add(i, 1);
    for (int i = 1; i <= q; ++i) {
        int x;
        cin >> x;
        if (s[x] == '1') {
            s[x] = '0';
            if (idx[x] != 0) add(idx[x], -1);
            sum -= 1;
        } else {
            s[x] = '1';
            if (idx[x] != 0) add(idx[x], 1);
            sum += 1;
        }
        cout << min(g, sum) - query(min(g, sum)) << endl;
    }
}

int main() {
    cin.sync_with_stdio(false);
    cin.tie(NULL);
    sol();
    return 0;
}