河南萌新联赛2024第(五)场:信息工程大学

河南萌新联赛2024第(五)场:信息工程大学

前言

有点水这场,原题和板子貌似有点多。。

A-日历游戏_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

首先不看年份的话,显然 \(8/1\) 败,\(7/31\) 胜,\(7/30\) 败,\(7/29\) 胜,\(\dots\),以此类推,就能发现一个 \((m+d)\bmod 2=0\) \((m为月,d为日)\) 时,必胜,\((m+d)\bmod 2=1\) 时必败的规律,但是要注意有两个特殊日期,就是 \(9/30\)\(11/30\)\(9/30\rightarrow 10/1\ or\ 10/30,11/30\rightarrow 12/1\ or \ 12/30\),可以控制下一次的奇偶性,在最优策略下可以控制必胜。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    int x, y, z;
    cin >> x >> y >> z;

    if ((y == 9 && z == 30) || (y == 11 && z == 30) || (y + z) % 2 == 0)
        cout << "YES\n";
    else
        cout << "NO\n";

}

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

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

B-学生分组_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

首先就是特判下平均数在不在 \([L,R]\) 的区间内。

然后就是去比较下所有数小于 \(L\) 和大于 \(R\) 的部分哪部分最大即可,最大的补在另一边,剩下补平均数即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

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

    int n;
    cin >> n;

    i64 sum = 0;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum += a[i];
    }

    i64 l, r;
    cin >> l >> r;

    if (sum / n < l || (sum + n - 1) / n > r) {
        cout << "-1\n";
        return 0;
    }

    i64 x = 0, y = 0;
    for (int i = 1; i <= n; i ++) {
        if (a[i] < l) x += l - a[i];
        else if (a[i] > r) y += a[i] - r;
    }

    cout << max(x, y) << '\n';

    return 0;
}

C-小美想收集_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

种类(扩展域)并查集的模板。

贪心的按冲突值从大到小排序,然后用并查集维护两个集合,以 \(x\)\(x+n\) 代表其自身的集合和它相对的集合,假设 \(a,b\) 冲突,那我们就把 \(a,b+n\) 连起来代表放一个集合里,\(b,a+n\) 放一个集合。

当枚举到的 \(a,b\) 如果在之前的分配中被分到一个集合了,那么此时它们的冲突值即是最大的,输出即可。

二分 + 二分图染色也可以写,具体的可以去看看P1525 [NOIP2010 提高组] 关押罪犯 这道题的题解。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

struct UFS {
    int sz;
    vector<int> rank, p;
    void link(int x, int y) {
        if (x == y)
            return;
        if (rank[x] > rank[y])
            p[y] = x;
        else
            p[x] = y;
        if (rank[x] == rank[y])
            rank[y]++;
    }
    void init(int n) {
        sz = n;
        rank.resize(n + 1);
        p.resize(n + 1);
        for (int i = 0; i <= sz; i++) {
            p[i] = i;
            rank[i] = 0;
        }
    }
    int find(int x) {
        return x == p[x] ? x : (p[x] = find(p[x]));
    }
    void unin(int x, int y) {
        link(find(x), find(y));
    }
    void compress() {
        for (int i = 0; i <= sz; i++)
            find(i);
    }
};
//种类并查集 merge(y + n, x),merge(x + n, y)

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

    int n, m;
    cin >> n >> m;
    vector<tuple<i64, int, int>> g;
    for (int i = 0; i < m; i ++) {
        i64 u, v, w;
        cin >> u >> v >> w;
        g.push_back({w, u, v});
    }

    sort(g.begin(), g.end(), greater<>());
    UFS ufs;
    ufs.init(2 * n);
    i64 ans = 0;
    for (int i = 0; i < m; i ++) {
        auto [w, u, v] = g[i];
        if (ufs.find(u) == ufs.find(v) || ufs.find(u + n) == ufs.find(v + n)) {
            ans = w;
            break;
        }
        ufs.unin(u + n, v);
        ufs.unin(v + n, u);
    }

    cout << ans << '\n';

    return 0;
}

D-区间问题1_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

普通线段树板题,树状数组差分也可以。

据说直接 \(O(qn)\) 差分都有人过了

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

template<class Node>
struct SegmentTree {
#define lc u<<1
#define rc u<<1|1
    const int n, N;
    vector<Node> tr;

    SegmentTree(): n(0) {}
    SegmentTree(int n_): n(n_), N(n * 4 + 10) {
        tr.reserve(N);
        tr.resize(N);
    }
    SegmentTree(vector<int> init) : SegmentTree(init.size()) {
        function<void(int, int, int)> build = [&](int u, int l, int r) {
            tr[u].l = l, tr[u].r = r;
            init_lazy(tr[u]);
            if (l == r) {
                tr[u] = {l, r, 0, init[l]};
                return ;
            }
            i64 mid = (l + r) >> 1;
            build(lc, l, mid);
            build(rc, mid + 1, r);
            pushup(tr[u], tr[lc], tr[rc]);
        };
        build(1, 1, n);
    }

    void cal_lazy(Node & fa, Node & ch) {
        i64 b = fa.add;
        ch.sum += b;
    }

    void tag_union(Node& fa, Node& ch) {
        i64 b = fa.add;
        ch.add += b;
    }

    void init_lazy(Node& u) {
        u.add = 0;
    }

    void pushdown(i64 u) {
        if (tr[u].add != 0) {
            cal_lazy(tr[u], tr[lc]);
            cal_lazy(tr[u], tr[rc]);
            tag_union(tr[u], tr[lc]);
            tag_union(tr[u], tr[rc]);
            init_lazy(tr[u]);
        }
    }

    void pushup(Node& U, Node& L, Node& R) { //上传
        U.sum = L.sum + R.sum;
    }

    void modify(int u, int l, int r, int k) {
        if (tr[u].l >= l && tr[u].r <= r) {
            tr[u].add += k;
            tr[u].sum += k;
            return ;
        }
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (l <= mid)
            modify(lc, l, r, k);
        if (r > mid)
            modify(rc, l, r, k);
        pushup(tr[u], tr[lc], tr[rc]);
    }

    Node query(int u, int l, int r) { //区查
        if (l <= tr[u].l && tr[u].r <= r)
            return tr[u];
        i64 mid = tr[u].l + tr[u].r >> 1;
        pushdown(u);
        i64 res = LLONG_MIN >> 1;
        if (r <= mid)
            return query(lc, l, r);
        if (l > mid)
            return query(rc, l, r);
        Node U;
        Node L = query(lc, l, r), R = query(rc, l, r);
        pushup(U, L, R);
        return U;
    }
};

struct Node { //线段树定义
    i64 l, r, add, sum;
};

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

    int n;
    cin >> n;

    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }

    SegmentTree<Node> tr(a);

    int q;
    cin >> q;
    while (q--) {
        int op;
        cin >> op;
        if (op == 1) {
            int l, r, d;
            cin >> l >> r >> d;
            tr.modify(1, l, r, d);
        } else {
            int x;
            cin >> x;
            auto ans = tr.query(1, x, x);
            cout << ans.sum << '\n';
        }
    }

    return 0;
}

E-哥德巴赫猜想_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

先筛出 \(5e4\) 以内的质数,然后枚举两个数,用 set 维护第三个数判断一下即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

//欧拉函数,质数
vector<int> euler_range(int n) {
    vector<int> phi(n + 1), prime;
    vector<bool> is_prime(n + 1, true);
    is_prime[1] = 0, phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) prime.push_back(i), phi[i] = i - 1;
        for (int j = 0; j < (int)prime.size() && i * prime[j] <= n; j++) {
            is_prime[i * prime[j]] = 0;
            if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            else {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
        }
    }
    return prime;
}

constexpr int N = 5e4 + 10, M = N - 5;
auto pr = euler_range(N);

set<int> s(pr.begin(), pr.end());

void solve() {

    int n;
    cin >> n;

    for (auto &i : pr) {
        for (auto &j : pr) {
            if (i + j >= n) break;
            if (s.count(n - i - j)) {
                cout << i << ' ' << j << ' ' << n - i - j << '\n';
                return ;
            }
        }
    }

    cout << "-1\n";

}

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

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

F-小美想跑步_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

把样例画个图可以发现,其实就是让你在有向图中找起到到其他点的最短距离,和其他点到起点的最短距离,正向存边跑 dijkstra 就是起点到到其他点的距离,反向存边跑 dijkstra 就是其他点到起点最短距离。

所以正反跑两遍 dijkstra 即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

struct DIJ {
    using i64 = long long;
    using PII = pair<i64, i64>;
    vector<i64> dis;
    vector<vector<PII>> G;

    DIJ() {}
    DIJ(int n) {
        dis.assign(n + 1, 1e18);
        G.resize(n + 1);
    }

    void add(int u, int v, int w) {
        G[u].emplace_back(v, w);
    }

    void dijkstra(int s) {
        priority_queue<PII> que;
        dis[s] = 0;
        que.push({0, s});
        while (!que.empty()) {
            auto p = que.top();
            que.pop();
            int u = p.second;
            if (dis[u] < -p.first) continue;
            for (auto [v, w] : G[u]) {
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    que.push({ -dis[v], v});
                }
            }
        }
    }
};

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

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

    DIJ dij1(n), dij2(n);
    for (int i = 0; i < m; i ++) {
        int u, v, w;
        cin >> u >> v >> w;
        dij1.add(u, v, w);
        dij2.add(v, u, w);
    }

    dij1.dijkstra(1);
    dij2.dijkstra(1);

    i64 ans = 0;
    for (int i = 2; i <= n; i ++) {
        ans += dij1.dis[i] + dij2.dis[i];
    }

    cout << ans << '\n';

    return 0;
}

G-爬楼梯_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

基础动态规划,经典爬楼梯问题。
\(f_i\) 表示爬到第 \(i\) 层的方案数。

\[f_i=f_{i-1}+f_{i-2}+f_{i-3} \]

代码

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

    int n;
    cin >> n;

    vector<Z> dp(n + 10, 0);
    dp[1] = 1, dp[2] = 2, dp[3] = 4;

    for (int i = 4; i <= n; i ++) {
        dp[i] += dp[i - 1] + dp[i - 2] + dp[i - 3];
    }

    cout << dp[n] << '\n';

    return 0;
}

H-区间问题2_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

卡常说实话有点逆天了。

貌似只有快读+ST表可以过,ST表还不能是封装的。

反正我线段树被卡成狗了

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

const int maxn = 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while (c < '0' || c > '9') {if (c == '-')f = -1; c = getchar();}
    while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x * f;
}

int Max[maxn][21];
int main() {
    int n = read();
    for (int i = 1; i <= n; i++) Max[i][0] = read();
    for (int j = 1; j <= 20; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; ++i)
            Max[i][j] = max(Max[i][j - 1], Max[i + (1 << (j - 1))][j - 1]);

    int l, r;
    int m = read();
    for (int i = 1; i <= m; ++i) {
        scanf("%d %d", &l, &r);
        int renk = log2(r - l + 1);
        int temp = max(Max[l][renk], Max[r - (1 << renk) + 1][renk]);
        printf("%d\n", temp);

    }

    return 0;
}

I-小美想打音游_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

就是选择一个 \(a\),使得所有数到它的绝对值距离最小,有这样一个定理:

将 a 的所有元素变为 a 的中位数是最优的。

貌似是叫中位数贪心,证明网上应该都能搜到。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

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

    int n;
    cin >> n;

    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }

    sort(a.begin() + 1, a.end());

    i64 avg = a[(n + 1) / 2];

    i64 ans = 1;
    for (int i = 1; i <= n; i ++) {
        ans += abs(a[i] - avg);
    }

    cout << ans << '\n';

    return 0;
}

J-平方根_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

签到。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

void solve() {

    i64 n;
    cin >> n;

    cout << (i64)sqrt(n) << '\n';

}

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

    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

K-小美想游泳_河南萌新联赛2024第(五)场:信息工程大学 (nowcoder.com)

思路

用堆优化的 dijkstra 在转移 \(dis\) 数组的时候将其用来维护路径最大值即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

struct DIJ {
    using i64 = long long;
    using PII = pair<i64, i64>;
    vector<i64> dis;
    vector<vector<PII>> G;

    DIJ() {}
    DIJ(int n) {
        dis.assign(n + 1, 1e18);
        G.resize(n + 1);
    }

    void add(int u, int v, int w) {
        G[u].emplace_back(v, w);
    }

    void dijkstra(int s) {
        priority_queue<PII> que;
        dis[s] = 0;
        que.push({0, s});
        while (!que.empty()) {
            auto p = que.top();
            que.pop();
            int u = p.second;
            if (dis[u] < -p.first) continue;
            for (auto [v, w] : G[u]) {
                if (dis[v] > max(dis[u], w)) {
                    dis[v] = max(dis[u], w);
                    que.push({ -dis[v], v});
                }
            }
        }
    }
};

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

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

    DIJ dij(n);
    for (int i = 0; i < m; i ++) {
        int u, v, w;
        cin >> u >> v >> w;
        dij.add(u, v, w);
        dij.add(v, u, w);
    }

    int s, t;
    cin >> s >> t;

    dij.dijkstra(s);

    cout << dij.dis[t] << '\n';

    return 0;
}
posted @ 2024-08-14 19:22  Ke_scholar  阅读(237)  评论(2编辑  收藏  举报