[CF1954] Educational Codeforces Round 164 (Rated for Div. 2) 题解

[CF1954] Educational Codeforces Round 164 (Rated for Div. 2) 题解

A. Painting the Ribbon

最优策略是染 \(\lceil \dfrac{n}{m} \rceil\) 个颜色,然后 Bob 会把剩下的都染成这个颜色

void work() {
    int n, m, k, c;
    cin >> n >> m >> k;
    c = (n + m - 1) / m;
    cout << (k >= n - c ? "NO" : "YES") << '\n';
    return ;
}

B. Make It Ugly

波动不超过一,答案是波动间隔的 \(min\)

int n, a[N];
vector<int> c;

void work() {
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    int x = a[1];
    a[0] = -1, a[n + 1] = -1;
    c.clear();
    c.push_back(0);
    for(int i = 1; i <= n; i ++) if(a[i] ^ x) c.push_back(i);
    c.push_back(n + 1);
    int mx = 1e9;
    for(int i = 1; i < c.size(); i ++) {
        mx = min(mx, c[i] - c[i - 1] - 1);
    }
    cout << (mx >= n ? -1 : mx) << '\n';
    
    return ;
}

C. Long Multiplication

和一定,差小积大。

D. Colored Balls

有趣的计数。

一个颜色集合的 value 是

\[\max(\max a_i, \lceil \dfrac{\sum a_i} 2 \rceil) \]

根据这个观察,我们可以计数 value 是 \(\max a_i\)\(\sum\) 的。

如果把 \(a\) 排序,那么可以设计一个懂得都懂的 01 背包,然后转移前计算 \(a_i\) 的贡献即可。

sort(a + 1, a + n + 1);
f[0] = 1;
for(int i = 1; i <= n; i ++) {
    for(int j = 0; j <= a[i]; j ++)
        ans = (ans + f[j] * a[i] % mod) % mod;
    for(int j = a[i] + 1; j <= 5000; j ++)
        ans = (ans + ((j + a[i] + 1) / 2) * f[j] % mod) % mod;
    for(int j = 5000; j >= a[i]; j --)
        f[j] = (f[j] + f[j - a[i]]) % mod;
}
cout << ans << '\n';

E. Chain Reaction

\(k = 1\) 是积木大赛,\(k > 1\) 就把 \(a_i\) 除以 \(k\) 上取整之后做积木大赛。

这是一个上取整整除分块的形式,\(a\) 的变化次数是 \(O(n\sqrt V)\) 级别的,差分数组的变化也是这个级别,用整除分块找到变化的时刻然后维护答案即可。

上取整整除分块与下取整唯一的不同就是如果 \(x\bmod r =0\),那么 \(r\) 会成为下一段的左端点,其它情况都会向上加一。

稍微卡常,时间复杂度:\(O(n\sqrt V)\)

// Problem: E. Chain Reaction
// Contest: Codeforces - Educational Codeforces Round 164 (Rated for Div. 2)
// Author: Moyou
// Copyright (c) 2024 Moyou All rights reserved.
// Date: 2024-04-12 23:31:10

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
// #define int long long
using namespace std;
const int N = 1e5 + 10;

int n, a[N], b[N], d[N], mx;
vector<int> c[N];
long long ans;
void chk(int k, int i) {
    b[i] = (a[i] + k - 1) / k;
    if(d[i] >= 0) ans -= d[i];
    d[i] = b[i] - b[i - 1];
    if(d[i] >= 0) ans += d[i];
    if(d[i + 1] >= 0) ans -= d[i + 1];
    d[i + 1] = b[i + 1] - b[i];
    if(d[i + 1] >= 0) ans += d[i + 1];
}
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i], b[i] = a[i], mx = max(mx, a[i]), d[i] = a[i] - a[i - 1];
    for(int i = 1; i <= n; i ++) if(d[i] >= 0) ans += d[i];
    for(int i = 1; i <= n; i ++) {
        bool flg = 0;
        for(int l = 1, r; l <= a[i]; l = r + 1) {
            r = a[i] / (a[i] / l);
            if(!flg) c[l].push_back(i);
            else flg = 0;
            if(a[i] % r == 0) {
                if(l != r) {
                    c[r].push_back(i);
                    flg = 1;
                }
            }
        }
    }
    cout << ans << ' ';
    for(int k = 2; k <= mx; k ++) {
        for(auto i : c[k]) chk(k, i);
        cout << ans << ' ';
    }

    return 0;
}

总结

打得还行,唯一的遗憾是 E 题没写完,主要是没写过上取整整除分块调了半天,后来用 STL 帮忙写还被卡常了,只能老老实实写上取整整除分块了·。

posted @ 2024-04-13 12:12  MoyouSayuki  阅读(449)  评论(0编辑  收藏  举报
:name :name