代码源挑战赛 Round 3

#13. [R3A]出现次数统计

#include <bits/stdc++.h>

using i64 = int64_t;
using vi = std::vector<i64>;
using std::cin, std::cout;

const int N = 5e5;

int main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    i64 n, x, res = 0;
    cin >> n >> x;
    for(i64 i = 1, y; i <= n; i ++) {
        cin >> y;
        res += (x == y);
    }
    cout << res;
    return 0;
}

#14. [R3B]k次幂求和

#include <bits/stdc++.h>

using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;

#define int i64
const int mod = 998244353;

int power(int x, int y) {
    int ans = 1;
    while (y) {
        if (y & 1) ans = ans * x % mod;
        x = x * x % mod, y /= 2;
    }
    return ans;
}

i32 main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, k;
    cin >> n >> k;
    int ans = 0;
    for (int i = 0, x; i < n; i++) {
        cin >> x;
        ans = (ans + power(x, k)) % mod;
    }
    cout << ans << "\n";
    return 0;
}

#15. [R3C]公因数求和

有一个很经典的式子,对于任何一个值\(x\),若被隐式分解后为

\[x = P_1^{c_1} \times P_2^{c_2} \dots P_m^{c_m} \]

\(x\)的所有因数和为

\[\Pi_{i=1} ^{m} (\sum_{j=0}^{c_i}P_i^j) \]

#include <bits/stdc++.h>

using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;

#define int i64
const int mod = 998244353;


i32 main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    int x, y;
    cin >> x >> y;
    int d = std::gcd(x, y);
    int res = 1;
    for(int i = 2; i * i <= d; i ++) {
        if(d % i != 0) continue;
        int k = 0;
        while(d % i == 0) k ++, d /= i;
        int ans = 0, x = 1;
        for(int j = 0; j <= k; j ++) {
            ans += x;
            x *= i;
        }
        res *= ans;
    }
    if(d != 1) res *= (d + 1);
    cout << res;
    return 0;
}

#16. [R3D]拼三角形

把所有的边排序,对于\(a < b < c\),则一定要满足\(len[a] + len[b] > len[c]\)

假设固定了\(a\),则对于\(b\)\(c\)来说,可以用双指针来求解。

#include <bits/stdc++.h>

using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;

#define int i64
const int mod = 998244353;

i32 main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vi len(n);
    for(auto &i : len) cin >> i;
    std::ranges::sort(len);

    int res = 0;
    for(int a = 0; a < n; a ++) {
        for(int b = a + 1, c = b + 1; b < n and c < n; b ++) {
            while(c + 1 < n and len[c + 1] < len[a] + len[b]) c ++;
            if(len[a] + len[b] > len[c]) res += c - b;
        }
    }
    cout << res << "\n";
    return 0;
}

#17. [R3E]知识点学习

一个比较有意思的树形dp。

枚举\(f[x][i]\)表示以\(x\)为根的子树选择\(i\)个点的最优解。

可以枚举子节点\(y\),以及子节点的选择\(j\)个,则有\(f[x][i] = f[x][i - j] + f[y][j]\)这样的转移。

这里要注意的一个点就是如果\(y\)被选择了\(x\)一定要被选择,所以\(j < i\)。但是有一种特殊的情况就是当\(x=0\)时,就可以\(j=i\)。因为0号点不计入点数中。

#include <bits/stdc++.h>

using i64 = long long;
using i32 = int32_t;
using vi = std::vector<i64>;
using std::cin, std::cout;

#define int i64
const int mod = 998244353;

i32 main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vi val(n + 1);
    for (int i = 1; i <= n; i++) cin >> val[i];
    std::vector<vi> e(n + 1);
    for (int i = 1, fa; i <= n; i++) {
        cin >> fa;
        e[fa].push_back(i);
    }
    vi size(n + 1, 1);
    size[0] = 0;

    std::vector f(n + 1, vi(n + 1, 0));
    auto dp = [&](auto &&self, int x) -> void {
        f[x][1] = val[x];
        for (auto y: e[x]) {
            self(self, y);
            for (int s = size[x] + size[y]; s >= 1; s--) {
                for (int b = std::max(s - size[x], 0LL); b <= size[y] and ((b < s) or (x == 0 and b <= s)); b++) {
                    int a = s - b;
                    f[x][s] = std::max(f[x][s], f[x][a] + f[y][b]);
                }
            }
            size[x] += size[y];
        }
        return;
    };
    dp(dp, 0);
    cout << f[0][m] << "\n";
    return 0;
}

posted @ 2025-05-13 23:29  PHarr  阅读(56)  评论(0)    收藏  举报