2025.5.27

刷题日记
前段时间忙着去打长春邀请赛了,没继续刷题
被打的道心破碎,回来下定决心要继续加训



Codeforces Round 1012 (Div.1) A. Simple Permutation
https://codeforces.com/problemset/problem/2089/A
要求构造一个1~n的排列p,使得数组c中至少有⌊n3⌋ − 1个素数,其中ci = ⌈(p1+p2+…+pi) / i⌉
这道题用到了一个数论中的定理:伯特兰假设
伯特兰假设:对任意自然数 n >= 2, 至少存在一个素数 p 使得 n < p < 2n
那么这道题的思路就是,先找一个素数a,然后依次填充a,a - 1,a + 1,a - 2,a + 2……即可
这样一来,c的前几位就全部都是素数,可以满足条件

点击查看代码
#include <bits/stdc++.h>

using ll = int64_t;
const ll N = 2e5 + 10;
const ll INF = LLONG_MAX;
const ll mod = 998244353;

inline bool prime (int x) {
    if (x == 1) return 0;
    if (x == 2) return 1;
    for (int i = 2; i <= sqrtl(x); i++) {
        if (x % i == 0) {
            return 0;
        }
    }
    return 1;
}

void solve () {
    int n;
    std::cin >> n;

    int len = n / 3 - 1;
    int tmp = (len - 1) / 2;
    int p = -1;

    for (int i = 1; i <= n; i++) {
        if (i - tmp >= 1 && prime(i)) {
            p = i;
            break;
        }
    }

    std::vector<int> ans;
    std::vector<int> vis(n + 1, 0);

    ans.push_back(p);
    vis[p] = 1;
    for (int i = 1; p + i <= n && p - i > 0; i++) {
        ans.push_back(p - i);
        ans.push_back(p + i);
        vis[p - i] = 1;
        vis[p + i] = 1;
    }

    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            ans.push_back(i);
        }
    }

    for (auto it : ans) {   
        std::cout << it << ' ';
    }
    std::cout << '\n';
}

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

    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}


Codeforces Round 1027 (Div.3) E. Kirei Attacks the Estate
https://codeforces.com/problemset/problem/2114/E
这道题是一个树形dp的简单题,要求是求任何一个点的垂直路径的最大值
实际上就是通过最小值和最大值递推一下,但一开始没意识到
用的dfs去搜索每一个点,喜提Time limit exceeded on test 7

点击查看代码
#include <bits/stdc++.h>

using ll = int64_t;
const ll N = 2e5 + 10;
const ll INF = LLONG_MAX;
const ll mod = 998244353;

void solve () {
    int n;
    std::cin >> n;

    std::vector<ll> danger(n + 1);
    std::vector<ll> list[n + 1];
    std::vector<ll> vis(n + 1, 0);
    std::vector<ll> tree[n + 1];
    std::vector<ll> ans(n + 1);

    for (int i = 1; i <= n; i++) {
        std::cin >> danger[i];
    }
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        std::cin >> u >> v;

        list[u].push_back(v); 
        list[v].push_back(u);
    }

    std::function<void(ll, ll)> del = [&] (ll now, ll fa) {
        for (auto next : list[now]) { 
            if (next != fa) {
                tree[next].push_back(now);
                del(next, now);  
            }   
        }
    };
    del(1, 0);

    ll res;
    std::function<void(ll, ll, ll)> dfs = [&] (ll now, ll tmp, ll flag) {
        for (auto next : tree[now]) {
            if (flag == 1) {
                res = std::max(res, tmp + danger[next]);
                dfs(next, tmp + danger[next], -1);
            }
            else if (flag == -1) {
                res = std::max(res, tmp - danger[next]);
                dfs(next, tmp - danger[next], 1);
            }
        }
        return;
    };

    for (int i = 1; i <= n; i++) {
        res = danger[i];
        dfs(i, danger[i], -1);
        ans[i] = res;
    }

    for (int i = 1; i <= n; i++) {
        std::cout << ans[i] << " \n"[i == n];
    }
}

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

    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}

后来看了队友的,改成了用bfs递推,过了

点击查看代码
#include <bits/stdc++.h>

using ll = int64_t;
const ll N = 2e5 + 10;
const ll INF = LLONG_MAX;
const ll mod = 998244353;

void solve () {
    int n;
    std::cin >> n;

    std::vector<ll> danger(n + 1);
    std::vector<ll> list[n + 1];
    std::vector<ll> vis(n + 1, 0);

    for (int i = 1; i <= n; i++) {
        std::cin >> danger[i];
    }
    for (int i = 1; i <= n - 1; i++) {
        int u, v;
        std::cin >> u >> v;
        list[u].push_back(v); 
        list[v].push_back(u);
    }

    std::queue<ll> q;
    std::vector<ll> max(n + 1);
    std::vector<ll> min(n + 1); 
    q.push(1);
    vis[1] = 1;
    max[1] = danger[1];
    min[1] = danger[1];

    while (q.size()) {
        auto now = q.front();
        q.pop();

        for (auto next : list[now]) {
            if (vis[next]) continue;

            max[next] = std::max(danger[next], danger[next] - min[now]);
            min[next] = std::min(danger[next], danger[next] - max[now]);
            vis[next] = 1;
            q.push(next);
        }
    }

    for (int i = 1; i <= n; i++) {
        std::cout << max[i] << " \n"[i == n];
    }
}

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

    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}

实际上就是,对于每个点都求一下他的最大代价和最小代价,然后他的父亲节点就可以用该节点的代价去递推
父节点最大代价 = max(父节点最大代价,danger[i] - 子节点最小代价)
父节点最小代价 = min(父节点最小代价,danger[i] - 子节点最大代价)
这样算到最后,每个点的最大代价就是答案了

posted @ 2025-05-27 22:04  _彩云归  阅读(33)  评论(0)    收藏  举报