Codeforces Round #588 (Div. 2)

本文精选了五道算法竞赛题目并提供了详细的题解,包括A-DawidandBagsofCandies、B-AniaandMinimizing、C-AnadiandDomino、D-MarcinandTrainingCamp和E-KamilandMakingaStream,涵盖了从简单到复杂的问题解决策略,适合初学者到进阶者学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A - Dawid and Bags of Candies

水题直接上代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 1e4 + 10;
 
int a[10];
 
int main() {
    int N = 4, sum = 0;
    
    for (int i = 1; i <= N; i++)
        scanf("%d", &a[i]), sum += a[i];
    sort(a + 1, a + 1 + N);
    
    if (sum % 2) cout << "NO" << endl;
    else {
        int t = sum / 2;
        if (a[4] == t || a[1] + a[4] == t) cout << "YES" << endl;
        else cout << "NO" << endl;
    }

    return 0;
}

B - Ania and Minimizing

水题直接上代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 2e5 + 10;
 
int N, K;
char s[MAX];
 
int main() {
    scanf("%d%d%s", &N, &K, s + 1);
    int cnt = 0;
    for (int i = 1; i <= N; i++) {
        if (cnt < K) {
            if (i == 1) {
                if (N != 1) printf("1");
                else printf("0");
                if (s[1] != '1')cnt++;
            }
            else {
                printf("0");
                if (s[i] != '0')cnt++;
            }
        }else printf("%d", s[i] - '0');
    }
    printf("\n");
	
    return 0;
}

C - Anadi and Domino

题解:
考虑给每一个点一个颜色,然后放Domino,求最多能放多少Domino
观察可以发现,如果 N ≤ 6 N\leq6 N6,每个点都染成不同的颜色,可选的Domino有15个(减去形如1-1的Domino),而 N = 6 N=6 N=6的情况下最多只有15条边,故直接输出边的数量即可
这里只需要考虑 N = 7 N=7 N=7的情况
能放最多的情况一定是:6个点颜色各不相同,2个点颜色相同
这里我们枚举一对点 i , j i,j i,j使得他们颜色相同,不妨就记为颜色1,那么颜色1能连出去的边有6种,分别是
1-1, 1-2, 1-3, 1-4, 1-5, 1-6,而现在我们的1-1已经用了(连接 i , j i,j i,j这两个点的边),所以实际上两个点是共用这剩下的5条边,而每条边只能用一次,所以如果这两个点 i , j i,j i,j都与点 k k k连通的话,只能选其中一个点与其连通,也就是说原来算放了2个domino,现在只能算放1个,也就是损失掉了,现在算现在只需要枚举,找出最小的损失即可。

代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 1e4 + 10;
 
int N, M;
int grap[10][10];
 
int main() {

    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N >> M;
    for (int i = 1; i <= M; i++) {
        int u, v; cin >> u >> v;
        grap[u][v] = grap[v][u] = 1;
    }
    if (N <= 6) cout << M;
    else {
        int minn = INF;//最小损失
        for (int i = 1; i <= N; i++) {//枚举i,j
            for (int j = i + 1; j <= N; j++) {
                int cnt = 0;
                for (int k = 1; k <= N; k++)//找出都连通的点
                    if (grap[i][k] && grap[j][k]) cnt++;
                minn = min(minn, cnt);//更新最小损失
            }
        }
        cout << M - minn;
    }
    cout << endl;
 
    return 0;
}

D - Marcin and Training Camp

题解:
显然如果有至少两个人的 a i a_i ai值相同,那么就不会出现这几个人歧视他人,所以值相同的人都可以加入集合 S S S,对于其他人 a i a_i ai,只要能在集合 S S S找到至少一个无法去歧视的人,就是 a i a_i ai这个人会的 a j a_j aj都会
,即 ( a i ∣ a j ) = a j , j ∈ S (a_i|a_j)=a_j,j∈S (aiaj)=aj,jS,那么就能加入集合。最后统计答案。
代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 7e3 + 10;

int N, tot;
ll s[MAX];
bool vis[MAX];

struct node {
    ll a, b;
    bool operator < (const node &num) const{
        return a < num.a;
    }
} point[MAX];

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N;
    for (int i = 1; i <= N; i++) cin >> point[i].a;
    for (int i = 1; i <= N; i++) cin >> point[i].b;
    sort(point + 1, point + 1 + N);//排序一下方便后面加入a值相同的

    ll ans = 0;

    for (int i = 1; i <= N; i++) {
        ll cnt = 1;
        while (i + 1 <= N && point[i].a == point[i + 1].a) {//相同的a
            vis[i] = 1;
            ans += point[i].b;
            cnt++;
            i++;
        }
        if (cnt > 1) {
            s[++tot] = point[i].a;//存入集合
            vis[i] = 1;
            ans += point[i].b;//加上答案
        }
    }

    for (int i = 1; i <= N; i++)
        if (!vis[i]) {//对于没有在集合里面的元素a_i
            for (int j = 1; j <= tot; j++)
                if ((point[i].a | s[j]) == s[j]) {//找到一个a_j,使得a_i会的a_j都会,那么就加入集合
                    ans += point[i].b;
                    break;
                }
        }


    cout << ans << endl;

    return 0;
}

E - Kamil and Making a Stream

题解:
这里直接dfs,每次一个一个算gcd然后统计是不行的(会T),得用 m p [ i ] mp[i] mp[i]存所有i和祖先节点gcd的值 及出现次数,这样可以大大减少计算次数,普通的记忆化搜索
代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
using namespace std;
typedef long long			ll;
typedef unsigned long long	ull;
typedef pair<int, int>		pii;
const int MAX = 1e5 + 10;
const int mod = 1e9 + 7;

int N;
ll ans, val[MAX];
map<ll, int> mp[MAX];//mp[i]保存所有 i和祖先节点gcd值 和 出现次数
int tot, head[MAX];

ll gcd(ll a, ll b) {
    if (a == 0 || b == 0)
        return max(a, b);
    ll c = a % b;
    while (c) {
        a = b;
        b = c;
        c = a % b;
    }
    return b;
}

struct {
    int nxt, to;
} e[MAX << 1];

void add(int u, int v) {
    e[++tot].nxt = head[u];
    e[tot].to = v;
    head[u] = tot;
}

void dfs(int u, int fa) {
    for (auto &it : mp[fa])//当前点加上和父亲节点gcd
        mp[u][gcd(val[u], it.first)] += it.second;
    mp[u][val[u]]++;//加上自己和自己gcd

    for (auto &it : mp[u])//统计答案
        (ans += it.first * it.second % mod) %= mod;

    for (int i = head[u]; i; i = e[i].nxt)//往下递归
        if (e[i].to != fa) dfs(e[i].to, u);

}

int main() {

    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N;
    for (int i = 1; i <= N; i++)
        cin >> val[i];
    for (int i = 1; i < N; i++) {
        int u, v; cin >> u >> v;
        add(u, v); add(v, u);
    }
    dfs(1, 0);
    cout << ans << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值