Codeforces Round #727 (Div. 2)部分题解

本文解析了Codeforces平台上的四道编程题,包括运动员比赛压力计算、字符串变换长度、学生分组优化及商品购买策略,提供了详细的算法思路和C++代码实现。

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

Problem - A - Codeforces

题目大意:有若干个运动员,他们参加的比赛持续时间为t,每个运动员在间隔x的时间后会进行参赛,例如有3个运动员,他们的参赛时刻就为0,x,2x,当一个运动员还在比赛的时候,其他运动员进入,会增加他们一点压力值,求最后所有运动员参加完比赛后的压力值之和.

思路:首先需要确定在一个运动员参赛过程中可能累计的最大压力值,为t/x向下取整,然后判断有多少个人是处于最大压力区间的,这个区间的大小是运动员总数减去区间内最大压力值,然后除满压力值的,其它每个人的压力值依次递减,就可以求出,还需要注意的是需要分类,如果没有人在满压力区间内,那么可能会出现负数,所以要改判一下.

#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
using namespace std;
ll t, n, c, x;

int main(){
    cin>>t;
    while(t--){
        ll ans = 0;
        cin>>n>>x>>c;
        ll every = c / x;
        ll num = n - every;	//满压力区间人数
        if (num >= 0){
            ans += every * num;
            ans += (n-num-1)*(n-num)/2;//递减序列
        }else{
            ans += (n-1)*n/2;
        }
        cout << ans <<endl;
    }

    return 0;
}

Problem - B - Codeforces

题目大意:给定一个字符串,求在指定区间内经过一定的变换后,字符串的长度,变换规则是,当前字符重复在字母表中的顺序数,例如a不重复,b重复一次.

思路:直接前缀和.

#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
int t, n;
using namespace std;
ll pre[100005];
string a;
int main(){
    cin>>n>>t;
    cin>>a;
    for (int i = 1; i <= n; ++i)pre[i] = pre[i-1] + (a[i-1]-'a')+1;

    while(t--){
        int a, b;
        cin>>a>>b;
        cout<<pre[b] - pre[a-1]<<endl;
    }

    return 0;
}

Problem - C - Codeforces

题目大意:一个队伍里每个学生有自己的能力值,按照能力值进行排序后,可以将学生们分成若干组,当一个有序小组中任意相邻的两学生能力值差值小于等于x时,才可以成为一个组,否者只能继续分组,你有k次机会,向队伍里添加任意能力值的学生.

思路:贪心,先对数组排个序,只要每次能力值超过了范围,那么就将差值入队,然后对所有的差值进行一个升序排序,每次处理差值最小的,因为每处理掉一个差值,小组数量就会减一,为了使减少的尽可能多,要先从小差值起手.

注意点:当两点之间差值为2x的时候,实际上只需要一个学生就够了,我wa的代码进行判断的时候,采用的是下面这种形式,算法没错但是x和k都是1e14,所以溢出之后答案就错了,应该采用除法求出当前需要添加的个数,然后对个数进行比较.

    for (int i = 0; i < index; ++i){
        if (dis[i] <= x*(k+1)){	//溢出
            ll num = dis[i] / x - (dis[i] % x == 0);
            k -=num;
            ans--;
        }else{
            break;
        }

ac代码如下

#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
int t, n;
using namespace std;
const int MAX = 2e5+5;
ll a[MAX];
ll dis[MAX];
ll k, x;
int main(){
    cin>>n>>k>>x;
    for (int i = 1; i <= n; ++i)cin>>a[i];
    sort(a+1, a+1+n);
    int index = 0;
    for(int i = 2; i <= n; ++i){
        if (a[i] - a[i-1] > x)dis[index++] = (a[i]-a[i-1]);
    }
    sort(dis, dis+index);
    ll ans = index+1;
    for (int i = 0; i < index; ++i){
        ll need = ((dis[i])-1)/x;   //一种简便写法,因为当正好被两倍整除的时候只需要一个学生插入
        if (need>k)break;
        else k -= need, ans--;
    }
    cout << ans <<endl;

    return 0;
}

Problem - D - Codeforces

题目大意:给定一些商品,每样商品的价值为2,每件商品有它所需要的购买量,每件商品有它的优惠数量,当你手上物品数量大于等于优惠量之后,就可以半价购买该种商品,请算出最少的购买价格.

思路:模拟题,直接双指针,先将商品进行排序,按优惠价格大进行降序排列,然后左指针来购买优惠量最大的,右指针判断折扣量,具体细节见代码.
注意:又溢出了,我吐了,不然上大分

#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
ll t, n;
const int MAXN = 1e5 + 5;
struct Good {
    ll num;
    ll discount;
};
bool cmp(const struct Good& a, const struct Good& b) {
    if (a.discount > b.discount)return true;
    else if (a.discount == b.discount) {
        return a.num > b.num;
    }return false;
}
Good goods[MAXN];

using namespace std;

int main() {
    cin >> n;
    rep(i, 1, n)cin >> goods[i].num >> goods[i].discount;
    sort(goods + 1, goods + 1 + n, cmp);
    ll ans = 0;
    int r = n, l = 1;
    ll now = 0;
    while (l <= r) {
        ll temp = max(goods[r].discount - now, (ll)0);	//判断当前具体右数量还差的优惠数量,优惠数量不能为负
        while (temp >= goods[l].num && l <= r) {	//如果当前左指针指向的物品全部买下都不够优惠,就继续循环
            ans += (ll)2 * goods[l].num;			//同时如果到最后没能凑齐优惠金额,要设置停止条件
            temp -= goods[l].num;
            now += goods[l].num;
            l++;
        }
        if (l > r)break;
        ans += temp * (ll)2;	//当前左指针指向的物品在满足了优惠数目后还有结余,先只计算优惠金额数目的量
        goods[l].num -= temp;
        now += temp;			//now一定要事实更新
        ans += goods[r].num;
        now += goods[r].num;
        r--;
    }
    cout << ans << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值