Codeforces 杂题集(其三)

 

记录一些没有写在其他随笔中的 Codeforces 杂题, 以 Problemset 题号排序

 

1427C - The Hard Work of Paparazzi(2000)
从网格起点 \((1,1)\) 出发,已知有 \(n\) 个目标分别在严格递增的指定时间 \(t_i\) 瞬间出现在坐标 \((x_i, y_i)\),在移动耗时等于两点间曼哈顿距离的条件下,求最多能准时赶到并访问多少个目标。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int r, n;
    cin >> r >> n;

    vector<array<int, 3>> a(n + 1);
    a[0] = {0, 1, 1};
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 3; j++) cin >> a[i][j];
    }

    vector<int> dp(n + 1, INT_MIN);
    dp[0] = 0;
    int pre_max = INT_MIN;
    for (int i = 1; i <= n; i++) {
        for (int j = max(i - 2 * r, 0); j < i; j++) {
            if (abs(a[i][1] - a[j][1]) + abs(a[i][2] - a[j][2]) <=
                a[i][0] - a[j][0]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        dp[i] = max(dp[i], pre_max + 1);
        if (i - 2 * r >= 0) pre_max = max(pre_max, dp[i - 2 * r]);
    }
 
    cout << *max_element(dp.begin(), dp.end()) << '\n';
}

 

1207F - Remainder Problem(2100)
维护一个初始全0的数组,支持单点加值(将 \(a_x\) 增加 \(y\)),以及查询所有下标模 \(x\) 等于 \(y\) 的元素之和。

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

using ll = long long;

const int N = 5e5;
const int SN = sqrt(N);

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    vector<int> a(N + 1);
    vector b(SN + 1, vector<int>(SN + 1));

    int q;
    cin >> q;

    while (q--) {
        int t, x, y;
        cin >> t >> x >> y;

        if (t == 1) {
            a[x] += y;
            for (int i = 1; i <= SN; i++) {
                b[i][x % i] += y;
            }
        } else {
            if (x <= SN) cout << b[x][y] << '\n';
            else {
                int ans = 0;
                for (int i = y; i <= N; i += x) {
                    ans += a[i];
                }
                cout << ans << '\n';
            }
        }
    }
}

 

1187C - Vasya And Array(1800)
已知一个未知数组的若干个子区间是否单调不降的限制条件,要求构造出一个满足所有限制的数组,或判断无解。

题解

不妨让整个数组是 \(n, n-1, n-2, ..., 1\),这样整个数组都是逆序。如果有查询确定一段区间是单调不降的,就让这个区间所有值都变成开头的那个数,这样就尽可能地不破坏大部分逆序。查询区间逆序时只要确认首位是否相等即可,因为整个数组都是单调不升的。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vector<array<int, 3>> v(m);
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < 3; j++) {
            cin >> v[i][j];
        }
        v[i][1]--;
        v[i][2]--;
    }

    sort(v.begin(), v.end(), [&](auto x, auto y) { return x[1] < y[1]; });

    vector<int> ans(n);
    iota(ans.rbegin(), ans.rend(), 1);
    for (auto [t, l, r] : v) {
        if (t == 1) {
            for (int i = l + 1; i <= r; i++) ans[i] = ans[i - 1];
        }
    }
    for (auto [t, l, r] : v) {
        if (t == 0) {
            if (ans[l] == ans[r]) {
                cout << "NO\n";
                return 0;
            }
        }
    }

    cout << "YES\n";
    for (int i = 0; i < n; i++) {
        cout << ans[i] << " \n"[i == n];
    }
}

 

1187E - Tree Painting(2100)
在一棵初始全白的树上,每次染黑一个与已有黑点相邻的白点(第一步可任选一点),并获得该点所在白色连通块大小的得分,求将全树染黑所能获得的最大总得分。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<vector<int>> adj(n);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    vector<int> dep(n), sz(n);
    auto dfs1 = [&](this auto&& self, int x, int p) -> void {
        sz[x] = 1;
        for (auto y : adj[x]) {
            if (y != p) {
                dep[y] = dep[x] + 1;
                self(y, x);
                sz[x] += sz[y];
            }
        }
    };
    dep[0] = 1;
    dfs1(0, -1);

    vector<ll> dp(n);
    dp[0] = accumulate(dep.begin(), dep.end(), 0LL);
    auto dfs2 = [&](this auto&& self, int x, int p) -> void {
        for (auto y : adj[x]) {
            if (y != p) {
                dp[y] = dp[x] - 2 * sz[y] + n;
                self(y, x);
            }
        }
    };
    dfs2(0, -1);

    cout << *max_element(dp.begin(), dp.end()) << '\n';
}

 

1157D - N Problems During K Days(1900)
给定正整数 \(n\)\(k\),要求构造一个长度为 \(k\)、元素之和为 \(n\) 的正整数序列 \(a\),且满足相邻两项 \(a_i < a_{i+1} \le 2a_i\),若无法构造则输出无解。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    ll n, k;
    cin >> n >> k;

    if (k == 1) {
        cout << "YES\n" << n << '\n';
        return 0;
    }

    n -= k * (k + 1) / 2;
    if (n < 0) {
        cout << "NO\n";
        return 0;
    }

    if (n == k - 1) {
        if (k == 2 || k == 3) {
            cout << "NO\n";
        } else {
            cout << "YES\n1 2 ";
            for (int i = 0; i < k - 3; i++) cout << i + 4 << ' ';
            cout << k + 2 << '\n';
        }
        return 0;
    }

    ll a0 = n / k + 1;
    ll r = n % k;

    cout << "YES\n";
    for (int i = 0; i < k - r; i++) cout << a0++ << ' ';
    a0++;
    for (int i = 0; i < r; i++) cout << a0++ << ' ';
}

 

1157E - Minimum Array(1700)
给定两个长度为 \(n\) 的数组 \(a\)\(b\),你需要重新排列数组 \(b\) 的元素,使得对应位置相加并对 \(n\) 取模生成的新数组 \(c\)(即 \(c_i = (a_i + b_i) \pmod n\))的字典序最小。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a(n);
    multiset<int> ms;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        ms.insert(x);
    }

    for (int i = 0; i < n; i++) {
        auto ite = ms.lower_bound(n - a[i]);
        if (ite == ms.end()) {
            ite = ms.begin();
        }
        cout << (a[i] + *ite) % n << " \n"[i + 1 == n];
        ms.erase(ite);
    }
}

 

1157F - Maximum Balanced Circle(2000)
从给定数组中选出最多的数排成一个环,使得环上任意相邻两数之差的绝对值都不超过 \(1\)

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a;
    map<int, int> mp;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        if (++mp[x] == 1) {
            a.push_back(x);
        }
    }

    sort(a.begin(), a.end());
    int max_len = 0, start, end;
    for (int i = 0, j; i < a.size(); i = max(i + 1, i + j - a[i])) {
        j = a[i];
        while (mp[j] >= 2) j++;
        int len = j - a[i];
        if (len > 0) {
            int cnt = 0;
            for (int k = a[i] - 1; k <= j; k++) cnt += mp[k];
            if (cnt > max_len) {
                max_len = cnt;
                start = a[i] - int(mp[a[i] - 1] > 0);
                end = j - int(mp[j] == 0);
            }
        }
    }
    if (max_len > 0) {
        deque<int> ans;
        for (int i = start; i <= end; i++) {
            int cnt = mp[i];
            while (cnt >= 2) {
                ans.push_back(i);
                ans.push_front(i);
                cnt -= 2;
            }
            if (cnt >= 1) {
                ans.push_back(i);
            }
        }
        cout << ans.size() << '\n';
        for (int e : ans) cout << e << ' ';
        return 0;
    }

    for (int i = 0; i + 1 < a.size(); i++) {
        if (a[i] + 1 == a[i + 1]) {
            cout << "2\n";
            cout << a[i] << ' ' << a[i] + 1 << '\n';
            return 0;
        }
    }

    cout << "1\n" << a[0] << '\n';
}

 

1155D - Beautiful Array(1900)
给定一个数组和一个整数 \(x\),你可以最多将其中一段连续子数组的所有元素乘以 \(x\),求操作后整个数组的最大连续子数组和

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, x;
    cin >> n >> x;

    ll dp0 = 0, dp1 = INT_MIN, dp2 = INT_MIN, ans = 0;
    for (int i = 0; i < n; i++) {
        ll a;
        cin >> a;
        ll nxt0 = max({a, a + dp0});
        ll nxt1 = max({a * x, a * x + dp0, a * x + dp1});
        ll nxt2 = max({a + dp1, a + dp2});
        dp0 = nxt0;
        dp1 = nxt1;
        dp2 = nxt2;
        ans = max({ans, dp0, dp1, dp2});
    }

    cout << ans << '\n';
}

 

1092C - Prefixes and Suffixes(1700)
给定一个未知字符串被打乱顺序的所有真前缀和真后缀(长度从 \(1\)\(n-1\)),要求将每个输入的子串正确分类为前缀('P')或后缀('S')。

题解

关键是判断长度是 \(n-1\) 的两个真前缀或真后缀到底谁是真前缀/真后缀,这样就知道整个串的内容了

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<string> v(2 * n - 2);
    string s1, s2;
    for (int i = 0; i < 2 * n - 2; i++) {
        cin >> v[i];
        if (v[i].size() == n - 1) {
            if (s1.empty()) {
                s1 = s2 = v[i];
            } else {
                s1 += v[i].back();
                s2 = v[i][0] + s2;
            }
        }
    }

    auto solve = [&](string s) {
        string ans;
        vector<int> vis(n);
        for (auto a : v) {
            int len = a.size();
            if (!vis[len] && s.substr(0, len) == a) {
                ans += 'P';
                vis[len] = 1;
            } else if (s.substr(n - len, len) == a) {
                ans += 'S';
            } else {
                return ""s;
            }
        }
        return ans;
    };

    string ans1 = solve(s1);
    if (ans1.size()) {
        cout << ans1 << '\n';
    } else {
        cout << solve(s2) << '\n';
    }
}

 

1092E - Minimal Diameter Forest(2000)
给定一个森林,要求添加边将其连通成一棵树,并使得最终生成的这棵树的直径最小。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vector<vector<int>> g(n);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<int> dep(n), par(n);

    auto dfs = [&](this auto&& self, int x, int p, int d) -> array<int, 2> {
        dep[x] = d;
        par[x] = p;
        array<int, 2> rt = {dep[x], x};
        for (auto y : g[x]) {
            if (y != p) {
                rt = max(rt, self(y, x, d + 1));
            }
        }
        return rt;
    };

    auto find_g = [&](int x) -> array<int, 2> {
        auto fp = dfs(x, -1, 1);
        fp = dfs(fp[1], -1, 1);
        int u = fp[1];
        for (int j = 0; j < fp[0] / 2; j++) {
            u = par[u];
        }
        return {fp[0], u};
    };

    vector<array<int, 2>> gs;
    for (int i = 0; i < n; i++) {
        if (dep[i] == 0) {
            gs.push_back(find_g(i));
        }
    }
    sort(gs.begin(), gs.end(), greater<>());

    vector<array<int, 2>> ans;
    for (int i = 1; i < gs.size(); i++) {
        auto [u, v] = array{gs[0][1], gs[i][1]};
        g[u].push_back(v);
        g[v].push_back(u);
        ans.push_back({u, v});
    }

    cout << find_g(0)[0] - 1 << '\n';
    for (auto [u, v] : ans) {
        cout << u + 1 << ' ' << v + 1 << '\n';
    }
}

 

1092F - Tree with Maximum Cost(1900)

给定一棵带点权的树,求选择一个中心节点,使得所有节点到该节点的距离与其自身权值乘积的总和(即 \(\sum dist(i,v) \cdot a_i\))最大。

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

using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a(n);
    ll sum_a = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        sum_a += a[i];
    }
    vector<vector<int>> edge(n);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        edge[u].push_back(v);
        edge[v].push_back(u);
    }

    vector<ll> sw(n), sdw(n);
    auto dfs1 = [&](this auto&& self, int x, int p) -> void {
        sw[x] = a[x];
        for (auto y : edge[x]) {
            if (y != p) {
                self(y, x);
                sw[x] += sw[y];
                sdw[x] += sw[y] + sdw[y];
            }
        }
    };

    dfs1(0, -1);

    auto dfs2 = [&](this auto&& self, int x, int p) -> void {
        for (auto y : edge[x]) {
            if (y != p) {
                sdw[y] += sdw[x] - (sdw[y] + sw[y]) + (sum_a - sw[y]);
                self(y, x);
            }
        }
    };

    dfs2(0, -1);

    cout << *max_element(sdw.begin(), sdw.end()) << '\n';
}
posted @ 2026-06-07 15:24  Linqi05  阅读(6)  评论(0)    收藏  举报