IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)

A. Kevin and Arithmetic

题目大意

给你一个数组,每次可以选择一个其中一个数字加给s(初始值是0),如果s是偶数可以加一分,之后不加分,一直将s/2直到s是奇数再继续操作,问最大的分数是多少

解题思路

由于不断执行s/2之后一定是一个奇数,所以只要加上奇数就能对答案贡献1,因此统计奇数的数量即可,需要额外处理第一次是偶数的情况

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int t;
    std::cin >> t;

    while (t--) {
        int n, even = 0, odd = 0;
        std::cin >> n;

        std::vector<int> a(n);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            if (a[i] % 2) {
                even += 1;
            } else {
                odd += 1;
            }
        }

        std::cout << (odd > 0) * 2 + even - 1 << "\n";
    }
}

B. Kevin and Geometry

题目大意

给你一个数组,选出四个数字组成等腰梯形并给出任意一个方案,不可能则输出-1

解题思路

想要构成等腰梯形只要满足上底加两腰大于下底即可(假设上底小于等于下底),因此可以贪心的选择最大的两腰,然后在剩余的数字中遍历出相邻的两个一直判断即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int t;
    std::cin >> t;

    while (t--) {
        int n, max2 = 0, f = 1;
        std::cin >> n;

        std::vector<int> a(n);
        std::map<int, int> mp;
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            if (mp[a[i]]) {
                max2 = std::max(max2, a[i]);
            }
            mp[a[i]]++;
        }

        std::sort(a.begin(), a.end());

        if (mp.size() == n) {
            std::cout << -1 << "\n";
        } else {
            a.erase(std::find(a.begin(), a.end(), max2));
            a.erase(std::find(a.begin(), a.end(), max2));

            for (int i = 1; i < n - 2 && f; i++) {
                if (a[i - 1] + max2 * 2 > a[i]) {
                    std::cout << a[i - 1] << " " << max2 << " " << max2 << " " << a[i] << "\n";
                    f = 0;
                }
            }

            if (f) {
                std::cout << -1 << "\n";
            }
        }
    }
}

C. Kevin and Puzzle

题目大意

给你一个数组a,第i个数字表示第i个人左侧有 ai 个说谎者(不包括自己),每个人要么是诚实的,要么是说谎者,队伍里不会有连续的说谎者,问有多少种方案满足,对答案模998244353

解题思路

每个人要么是诚实的,要么是说谎者,假设第i个人是诚实,第i-1个人也是诚实的,则将i-1诚实方案数累加到i诚实方案数,如果第i-1个人是说谎者,将i-1的说谎方案数加到i诚实方案数(不能有连续说谎者);假设第i个人是说谎者,i-1只能是诚实的(不能有连续说谎者),将i-1的诚实方案数加到i说谎方案数即可。dp下去就能得到最后的答案

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 998244353;

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

    int t;
    std::cin >> t;

    while (t--) {
        int n;
        std::cin >> n;

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

        std::vector<std::vector<int>> dp(n + 1, std::vector<int>(2));
        dp[1][0] = 1;
        dp[1][1] = a[1] == 0;
        for (int i = 2; i <= n; i++) {
            // i诚实
            if (a[i] == a[i - 1]) {
                dp[i][1] = (dp[i][1] + dp[i - 1][1]) % MOD;
            }
            if (a[i] == a[i - 2] + 1) {
                dp[i][1] = (dp[i][1] + dp[i - 1][0]) % MOD;
            }

            // i说谎
            dp[i][0] = (dp[i][0] + dp[i - 1][1]) % MOD;
        }

        std::cout << (dp[n][0] + dp[n][1]) % MOD << "\n";
    }
}

D. Kevin and Numbers

题目大意

给你两个数组ab,你可以在a中选两个绝对值不大于1的数合并,进行操作,问a能不能变成b

解题思路

正难则反,a能不断合并变成b,b也能不断分解变成a,只需要统计ab元素,将b中的元素不断分解与a匹配即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int t;
    std::cin >> t;

    while (t--) {
        int n, m;
        std::cin >> n >> m;

        std::map<int, int> mp1, mp2;
        std::vector<int> a(n), b(m);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            mp1[a[i]]++;
        }
        for (int i = 0; i < m; i++) {
            std::cin >> b[i];
            mp2[b[i]]++;
        }

        if (std::accumulate(a.begin(), a.end(), 0ll) != accumulate(b.begin(), b.end(), 0ll)) {
            std::cout << "No\n";
            continue;
        }

        while (!mp2.empty() && n) {
            auto [x, y] = *mp2.rbegin();
            mp2.erase(x);
            if (mp1.count(x)) {
                int match = std::min(mp1[x], y);
                mp1[x] -= match;
                y -= match;
                n -= match;
                if (mp1[x] == 0) {
                    mp1.erase(x);
                }
            }
            
            if (y) {
                if (x == 1) {
                    break;
                }
                mp2[x / 2] += y;
                mp2[x - x / 2] += y;
            }
        }

        if (!n) {
            std::cout << "Yes\n";
        } else {
            std::cout << "No\n";
        }
    }
}

E. Kevin and And

题目大意

给你两个数组ab,你可以执行k次操作,每次操作在ab中分别选两个数字让 ai = ai & bj,问a求和的最小值

解题思路

显然操作的次数越多最后求和会是单调不递增的,所以可以让操作次数拉满。观察数据范围发现m的范围非常小,因此可以考虑状压,枚举b数组选择的所有状态,预处理出选择的子集,再枚举选择的子集带给 ai 的影响并将每一次增加的操作带来的变化放入优先队列,贪心地选择即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int t;
    std::cin >> t;

    while (t--) {
        int n, m, k;
        std::cin >> n >> m >> k;

        std::vector<int> a(n), b(m);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
        }
        for (int i = 0; i < m; i++) {
            std::cin >> b[i];
        }

        std::vector<int> sum(1 << m, (1 << 30) - 1);
        for (int bit = 0; bit < (1 << m); bit++) {
            for (int j = 0; j < m; j++) {
                if (bit >> j & 1) {
                    sum[bit] &= b[j];
                }
            }
        }

        std::priority_queue<int> pq;
        for (int i = 0; i < n; i++) {
            std::vector<int> dp(m + 1);
            for (int bit = 0; bit < (1 << m); bit++) {
                int cnt = __builtin_popcount(bit);
                dp[cnt] = std::max(dp[cnt], a[i] ^ (a[i] & sum[bit]));
            }
            for (int j = 0; j < m; j++) {
                pq.push(dp[j + 1] - dp[j]);
            }
        }

        i64 ans = accumulate(a.begin(), a.end(), 0ll);
        while (!pq.empty() && k--) {
            ans -= pq.top();
            pq.pop();
        }
        
        std::cout << ans << "\n";
    }
}
posted @   udiandianis  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
  1. 1 山海不可平 CMJ
山海不可平 - CMJ
00:00 / 00:00
An audio error has occurred.

纯音乐,请欣赏

点击右上角即可分享
微信分享提示