Codeforces Round 1050 (Div. 4) 题解

A

图灵测试题,做不出来的可以被判定为机器人了。

直接判断 \(n\) 的奇偶分情况做即可。

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long

int n, x;

void solve () {
    cin >> x >> n;
    if (n&1) { cout << x << "\n"; return; }
    else cout << 0 << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}

B

有点小唬人啊这题,不过照样是图灵测试题。

不难发现无论怎么走,无论斜着走还是一个直角走也好,最优的情况都是把所有的 Laser 都经过一遍。

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
const int N = 2e5+100;

int n, m, x, y;
int a[N], b[N];

void solve () {
    cin >> n >> m >> x >> y;
    for (int i = 1;i <= n;i++) cin >> a[i];
    for (int i = 1;i <= m;i++) cin >> b[i];
    cout << n+m << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}

C

em,有点小恶心,不过大体是分类讨论。想到如果剩余奇数时间我们可以直接到达另一边,如果是偶数时间我们可以直接到达原来的边。

于是可以想到当目标边和我们原边一样的时候,考虑能得到的最大的偶数时间,不同时则考虑能得到的最大的奇数时间。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair <int, int>
const int N = 2e5+100;

ll n, m;
pii op[N];

void solve () {
    cin >> n >> m;
    for (int i = 1;i <= n;i++) cin >> op[i].first >> op[i].second;
    ll now = 0, side = 0, ans = 0;
    for (int i = 1;i <= n;i++) {
        if (op[i].first > m) break;
        ll minu = op[i].first - now;
        if (side == op[i].second) {
            if (minu&1) ans += (minu-1);
            else ans += minu;
        } else {
            if (minu&1) ans += minu;
            else ans += (minu-1);
        }
        now = op[i].first, side = op[i].second;
    }
    if (now < m) ans += (m - now);
    cout << ans << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}

D

小小思维题,通过题意不难发现,如果没有奇数那么无法得到任何除了 \(0\) 以外的答案。

此时考虑有奇数的情况,不难发现因为经过奇数就会改变状态,于是考虑一开始去添加偶数的时候经过的奇数是最大的,然后关闭时经过的偶数是最小的,然后以此类推,让大的对应小的即可。

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
const int N = 2e5+100; 

int n, a[N];

bool cmp (int x, int y) {
    return x > y;
}

void solve () {
    cin >> n;
    int cnt = 0;
    for (int i = 1;i <= n;i++) {
        cin >> a[i];
        if (a[i] & 1) cnt++; 
    }
    if (!cnt) { cout << "0\n"; return; }
    ll ans = 0;
    for (int i = 1;i <= n;i++) 
        if (!(a[i]&1)) ans += a[i], a[i] = 0;
    sort(a+1, a+n+1, cmp);
    deque <int> q;
    for (int i = 1;i <= n;i++) 
        if (a[i]) q.push_back(a[i]);
    if (q.size() == 1) ans += q.back();
    else {
        while (!q.empty() && q.size() > 1) {
            ans += q.front();
            q.pop_front();
            q.pop_back();
        }
        if (q.size() == 1) ans += q.back();
    }
    cout << ans << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}

E

滑动窗口的偏模板题,不难发现每一个数字都有其出现的次数限制,只需要在窗口滑动的过程中记录一下每一个数字的出现次数即可,如果有不符合要求的数字就右移左端点急么,答案就是左右端点中的 \([l, l], [l, l+1], \dots, [l, r]\),这样子计算可以避免重复和漏算。

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
const int N = 2e5+100;

int n, k, a[N], cnt[N], de[N];

void solve () {
    cin >> n >> k;
    memset(cnt, 0, sizeof(cnt));
    memset(de, 0, sizeof(de));
    // cout << "[+] " << n << '-' << k << "\n";
    for (int i = 1;i <= n;i++) {
        cin >> a[i];
        cnt[a[i]]++;
    }
    for (int i = 1;i <= n;i++) 
        if (cnt[i]) {
            if (cnt[i]%k) { cout << "0\n"; return; }
            de[i] = cnt[i] / k;
        }
    // for (int i = 1;i <= n;i++) cout << de[i] << " ";
    // cout << "\n";
    memset(cnt, 0, sizeof(cnt));
    ll ans = 0;
    int l = 1, r = 1;
    while (l <= r && r <= n) {
        cnt[a[r]]++;
        while (cnt[a[r]] > de[a[r]]) cnt[a[l]]--, l++;
        ans += (r-l+1);
        r++;
    }
    cout << ans << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}

F

stl 魅力时刻。

直接用 vector 来存输入,然后模拟排序,每次我就选我要的目标位置的最小字典序。

举个例子:第一次我要选择第一个位置上的字母,此时整个 ans 的字符串都是空的,所以我们考虑直接把字典序最小的塞进去。假设我们塞得字符串的长度为 \(len\),那么我们要考虑的索引就变为了 \(len\)(假设下标从 \(0\) 开始),然后将剩余的数字串都只保留 \(len\) 这个索引之后的(包括这个索引),以此类推。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long

int n;

void solve () {
    cin >> n;
    vector <vector <int> > a(n);
    int maxn = 0, pos = 0;
    for (int i = 0;i < n;i++) {
        int k; cin >> k;
        for (int j = 0;j < k;j++) {
            int x; cin >> x;
            a[i].push_back(x);
        }
        maxn = max(maxn, k);
    }

    vector <int> ans(maxn);
    while (pos < maxn) {
        sort(a.begin(), a.end());
        for (int i = 0;i < a[0].size();i++) ans[pos++] = a[0][i];
        vector <vector <int> > b;
        int now = a[0].size();
        for (int i = 1;i < a.size();i++) {
            vector <int> c;
            for (int j = now;j < a[i].size();j++) c.push_back(a[i][j]);
            if (c.size()) b.push_back(c);
        }
        a = b;
    }
    for (auto tmp : ans) cout << tmp << " ";
    cout << "\n";
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1; cin >> _;
    while (_--) solve();
    return 0;
}