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

MoyouSayuki發表於2024-04-13

[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 幫忙寫還被卡常了,只能老老實實寫上取整整除分塊了·。

相關文章