Codeforces Round #508 (Div. 2)

本文深入解析了CF竞技编程挑战中的四个题目,包括最长得1-K字母子序列、非互质分区、赌博博弈策略及黏菌生长问题。文章提供了详细的算法思路与代码实现,适合编程爱好者及竞赛选手学习。

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

昨天的cf,被一堆烦心事搞得自己很无语。。又打了一场半夜的cf,发现自己还是菜的一匹,哎。

A. Equality
最长的1-K,字母相同的最长子序列。
直接找到1-K字母最少的各数乘以K就可了。

B. Non-Coprime Partition
把1-N分给两个集合,使得两个集合的和的gcd大于1。1,2的时候直接特判无解。当N大于2的时候,只要把一个集合全部分配奇数,另一个集合全部非配偶数,这样就肯定正确。
因为对于连续的几个数字,比如1,2,3,4,5,无论奇数的和或者偶数的和一定是中间那个数的倍数。

C. Gambling
一道博弈,两个人玩游戏,有两个操作,删去对方列表一个数,或者拿自己列表一个数。问最后游戏结束后A手里的数减去B手里的数后为多少。
把列表里的数放到一个大顶堆里面就可以了,考虑自己堆里面的最大值和对方对立面的最大值比较,如果自己的大,就拿自己的这个数,否则删去对方的这个数。注意考虑一下堆为空的情况。

代码如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
int main(void){
    priority_queue<int,vector<int>,less<int> > A,B;
    int N,a,b;
    scanf("%d",&N);
    for(int i=1;i<=N;++i){
        scanf("%d",&a);
        A.push(a);
    }
    for(int i=1;i<=N;++i){
        scanf("%d",&b);
        B.push(b);
    }
    ll reA = 0,reB = 0;
    int round = 0;
    while(true){
        if(A.size() == 0 && B.size() == 0){
            break;
        }
        if(round % 2 == 0){
            if(B.size() == 0){
                reA += A.top();
                A.pop();
            }
            else if(A.size() == 0){
                B.pop();
            }
            else{
                if(A.top() >= B.top()){
                    reA += A.top();
                    A.pop();
                }
                else{
                    B.pop();
                }
            }
        }
        else{
            if(A.size() == 0){
                reB += B.top();
                B.pop();
            }
            else if(B.size() == 0){
                A.pop();
            }
            else{
                if(B.top() >= A.top()){
                    reB += B.top();
                    B.pop();
                }
                else{
                    A.pop();
                }
            }
        }
        round++;
    }
    printf("%I64d\n",reA-reB);
    return 0;
}

D. Slime
给你N个数,每个数可以减去左边的数或者右边的数,问你最后能产生的最大结果是多少。
这个题目昨天被我读错了。。理解为只能向右吃,结果一直没有通过。。。

思路:
考虑一个正数和一个负数,那么肯定结果是正数,所以,如果列表中既有正数又有负数,那么结果一定是所有数的绝对值的和。
现在考虑全为负数,那么一定是从最大的那个负数向两边减去,相当于加上两边数的绝对值。
如果全为正数,那么就是从最小的那个正数,向一边减去,产生最大的负数,最后被一个正数给吃掉,也相当于是加上两边的绝对值。

这样就可以分三种情况进行计算了。
代码也很好写,注意考虑N=1,要进行特判。
代码如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX = 5e5+10;
const ll INF = 1e16+10;
int N;
ll a[MAX];
int main(void){
    ll Min = INF,Max = -INF;
    int C1 = 0,C2 = 0;
    scanf("%d",&N);
    ll sum = 0;
    for(int i=1;i<=N;++i){
        scanf("%I64d",&a[i]);
        sum += abs(a[i]);
        if(a[i] > Max)  Max = a[i];
        if(a[i] < Min)  Min = a[i];
        if(a[i] <= 0)    C1++;
        if(a[i] >= 0)    C2++;
    }
    if(N == 1){
        printf("%I64d\n",a[1]);
    }
    else{
        if(C1 == N)
            sum += 2*Max;
        else if(C2 == N)
            sum -= 2*Min;
        printf("%I64d\n",sum);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值