Codeforces Round 984 (Div. 3) 题解

A

人类测试,写不出的是机器人。

B

不难发现,似乎一个架子是可以无限放同种品牌的饮料的,所以我们考虑将同种的瓶子缩在一起来看,然后拍个序,贪心从大到小来放置即可。

其实也是人类测试题。

#include <bits/stdc++.h>
#include <queue>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pii pair <int, int> 

void solve () {
    int n, k; cin >> n >> k;
    // vector <pii> wat(k+1);
    vector <int> cost(k+1);
    priority_queue <int, vector<int>, less<int> > q;
    for (int i = 1;i <= k;i++) {
        int ind, co;
        cin >> ind >> co;
        cost[ind] += co;
    }
    // sort()
    for (auto tmp : cost) {
        if (!tmp) continue;
        q.push(tmp);
    }
    ll ans = 0;
    // while (!q.empty()) { cout << q.top() << " "; q.pop(); }
    // cout << "[+]\n";
    for (int i = 1;i <= n && q.size();i++) 
        ans += q.top(), q.pop();
    cout << ans << "\n";
}

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

C

数据量并不大,我们首先统计出最初有多少 1100 存在,然后根据每一次的统计去看统计的位置的 \([i-3, i+3]\) 区间内出现了多少个 1100,然后最后再给出答案。

同时注意边界问题。

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

void solve () {
    string s; cin >> s;
    int len = s.size();
    int cnt = 0;
    for (int i = 0;i < len-3;i++) 
        if (s[i] == '1' && s[i+1] == '1' && s[i+2] == '0' && s[i+3] == '0') cnt++;
    int q; cin >> q;
    for (int j = 1;j <= q;j++) {
        int i; char v; cin >> i >> v;
        i--;
        int st = max(0, i-3), ed = min(len-4, i);
        for (int z = st;z <= ed;z++) 
            if (s[z] == '1' && s[z+1] == '1' && s[z+2] == '0' && s[z+3] == '0') cnt--;
        s[i] = v;
        for (int z = st;z <= ed;z++) 
            if (s[z] == '1' && s[z+1] == '1' && s[z+2] == '0' && s[z+3] == '0') cnt++;
        if (cnt) cout << "YES\n";
        else cout << "NO\n";
    }
}

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

D

没什么好说的,硬模拟一圈圈地往里面推进就行了。

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

char mp[N][N];

void solve () {
    int n, m; cin >> n >> m;
    for (int i = 1;i <= n;i++) 
        for (int j = 1;j <= m;j++)
            cin >> mp[i][j];
    int tn = n, tm = m, posi = 1, posj = 1;
    ll ans = 0;
    // cout << n << "----" << m << "\n";
    while (tn && tm) {
        string s;
        s = "";
        // cout << "[+] " << posj << " " << m << "\n";
        for (int i = posj;i <= m-posj+1;i++) 
            s += (mp[posi][i]);
        for (int i = posi+1;i <= n-posi;i++)
            s += (mp[i][m-posj+1]);
        for (int i = m-posj+1;i >= posj;i--)
            s += (mp[n-posi+1][i]);
        for (int i = n-posi;i >= posi+1;i--) 
            s += (mp[i][posj]);
        posi++, posj++; tn -= 2, tm -= 2;
        // ans = 0;
        // cout << s << "\n";
        int len = s.size();
        if (len < 4) break;
        for (int i = 0;i < len-3;i++) if (s[i] == '1' && s[i+1] == '5' && s[i+2] == '4' && s[i+3] == '3') ans++;
        if (s[len-3] == '1' && s[len-2] == '5' && s[len-1] == '4' && s[0] == '3') ans++;
        if (s[len-2] == '1' && s[len-1] == '5' && s[0] == '4' && s[1] == '3') ans++;
        if (s[len-1] == '1' && s[0] == '5' && s[1] == '4' && s[2] == '3') ans++;
        // cout << ans << "\n";
    }
    cout << ans << "\n";
}

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

E

首先不难发现,因为都默认往编号更大的国家流,同时用的是按位或运算,所以我们不难发现这是一个单调不减的二维数组(具体是在每一个区域的不同国家上面)。

然后发现我们可以用个双指针得到一个符合这么多条件的区间,如果区间的左右边界互驳就是无解,否则输出左边界即可(这个区间是在递增的国家编号上的)。

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

// int mp[N][N];
// pii mp2[N][N];
// int b[N][N];

void solve()
{
    int n, k, q;
    cin >> n >> k >> q;
    // vvi b(k, vi(n));
    vector <vector <int>> b(k, vector <int> (n));
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < k; j++)
        {
            cin >> b[j][i];
        }
    }
    for (int j = 0; j < k; j++)
    {
        for (int i = 1; i < n; i++)
        {
            b[j][i] = b[j][i - 1] | b[j][i];
        }
    }
    while (q--)
    {
        int m;
        cin >> m;
        int mn = 1;
        int mx = n;
        for (int i = 0; i < m; i++)
        {
            int r;
            char o;
            int c;
            cin >> r >> o >> c;
            int p = r - 1;
            if (o == '<')
            {
                auto &v = b[p];
                int pos = lower_bound(v.begin(), v.end(), c) - v.begin();
                mx = min(mx, pos);
            }
            else if (o == '>')
            {
                auto &v = b[p];
                int pos = upper_bound(v.begin(), v.end(), c) - v.begin();
                mn = max(mn, pos + 1);
            }
        }
        if (mn <= mx && mn <= n && mx >= 1)
            cout << mn << "\n";
        else
            cout << "-1\n";
    }
}


// void solve () {
//     int n, k, q;
//     cin >> n >> k >> q;
//     int maxn = max(n, k);
//     // vector <vector <int> > mp(maxn+1);
//     // cout << maxn << "\n";
//     for (int i = 0;i < n;i++)
//         for (int j = 0;j < k;j++) 
//             cin >> mp[i][j];
//     for (int j = 0;j < k;j++) {
//         int tmp = 0;
//         for (int i = 0;i < n;i++) tmp = tmp | mp[i][j], mp[i][j] = tmp;
//     }
//     // vector <vector <pii> > mp2;
//     for (int i = 0;i < n;i++)
//         for (int j = 0;j < k;j++)
//             mp2[j][i] = {mp[i][j], i};
//     auto cmp = [&](pii x, pii y) -> bool {
//         return x.first < y.first;
//     };
//     for (int j = 0;j < k;j++) sort(mp2[j], mp2[j]+n, cmp);
//     for (int j = 0;j < k;j++) {
//         for (int i = 0;i < n;i++) cout << mp2[j][i].first << " ";
//         cout << "\n";
//     }
//     for (int i = 1;i <= q;i++) {
//         int m; cin >> m;
//         map <int, int> cnt;
//         while (m--) {
//             int r, c; char op;
//             cin >> r >> op >> c; --r;
//             // cout << "[+] " << c << "\n";
//             if (op == '>') {
//                 for (int i = n-1;i >= 0;i--) if (mp2[r][i].first > c) cnt[mp2[r][i].second]++, cout << "[+] " << mp2[r][i].first << "\n";
//             } else {
//                 for (int i = 0;i < n;i++) if (mp2[r][i].first < c) cnt[mp2[r][i].second]++;
//             }
//         }
//         bool flag = false;
//         // for (int i = 1;i <= n;i++) 
//             // cout << cnt[i] << "\n";
//         if (!flag) cout << "-1\n";
//     }
// }

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

F

哇,恶心数学题。

首先我们先看个东西,当我们手玩几组异或会发现:

\[0 \oplus 1 \oplus 2 \oplus 3 = 0 \]

\[4 \oplus 5 \oplus 6 \oplus 7 = 0 \]

发现没,从零开始的自然数四个连续的可以异或成 \(\bm0\)

这个时候我们想想跟 \(2^i\) 同余的数字,会发现这些数字它的后 \(i\) 位都是相等的,只有前面的位置是不同的,而且因为两个同余的数字之间相隔的是 \(2^i\),所以他们的前面的二进制位其实是连续的,跟上面的写的式子的形式是一致的,形如:

\[00、01、10、11 \]

这个时候我们可能想到如果直接从 \(l \to r\) 可能不会得到如上的东西,但是我们转念一想,利用容斥原理,有趣的数字的异或和只需要用总异或和异或掉无趣数字的异或和即可,而且异或是满足前缀的性质的,所以我们可以用差分,所以我们可以从 \(1\) 开始!而且我们继续手玩异或,不难发现我们可以从 \(1\) 开始想,将 \(0\) 象征性的补到后面一位,得到的就是:

\[ f(n) = \begin{cases} n & n \mod 4 = 0 \\ 1 & n \mod 4 = 1 \\ n+1 & n \mod 4 = 2 \\ 0 & n \mod 4 = 3 \end{cases}\]

同时记住,这只是看了前面的位置而已,我们还要把我们丢掉的 \(i\) 通过左移拿回来,然后后面的 \(i\) 位只需要看看无趣数字的数量是偶数还是奇数了。因为哦我们考虑到可能在 \(\div 2^i\) 后可能还有余数,所以我们直接提前减掉 \(k\),然后可以在之后 \(+1\) 补回来。

所以最后的式子就是:

\[g(n, i, k) = f(\lfloor \frac{n-k}{2^i}\rfloor) \oplus k[\lfloor \frac{n-k}{2^i}\rfloor+1 \ \mod 2 = 1] \]

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

void solve () {
    ull l, r, i, k; cin >> l >> r >> i >> k;

    auto f = [&](ull n) -> ull {
        if (!(n%4)) return n;
        else if (n % 4 == 1) return 1;
        else if (n % 4 == 2) return n + 1;
        else return 0;
    };
    auto g = [&](ull n, ull i, ull k) -> ull {
        if (!i) {
            if (!k) return f(n);
            else return 0;
        } 
        ull pow2 = 1ULL << i;
        if (n < k) return 0;
        ull m = (n-k)/pow2, cnt = m+1, res = f(m) << i;
        if (cnt&1) res ^= k;
        return res;
    };

    ull sum = f(r) ^ f(l-1);
    ull minu = g(r, i, k) ^ g(l-1, i, k);
    cout << (sum ^ minu) << "\n";
}

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