Codeforces Round #782 (Div. 2)(A-C)题解

文章提供了三道编程竞赛题目,分别涉及构造只包含R和B的字符串,最大化按字典序排序的二进制串,以及计算最小迁都代价。解题思路包括利用字符串的性质、贪心策略和成本比较来优化解决方案。

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

A. Red Versus Blue

题目链接:Problem - A - Codeforces

题意:要求你构造一串字符串,只有‘R’和‘B’组成,告诉你总长度以及‘R’的数量和‘B’的数量,且‘R’的数量一定比‘B’多,且构造的字符串中要求所有连续‘R’的长度尽可能的短。

思路:‘B’有x个,那么就可以构造出x+1段,构造的时候注意每段‘R’的长度就行。

AC code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, r, b;
void solve()
{
    cin >> n >> r >> b;
    int cnt=0;
    int t=r/(b+1);
    int tt=r%(b+1);
    int x=0;
    while(cnt<n){
        x++;
        for(int i=0;i<t && cnt<n;i++) cout<<"R",cnt++;
        if(x<tt) cout<<"R",cnt++;
        if(b>0){
            cout<<"B";
            b--;
            cnt++;
        }
    }
    cout<<endl;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while(T--)
    {
        solve();
    }
    return 0;
}

B. Bit Flipping

题目链接:Problem - B - Codeforces

题意:给你一个二进制串,你有k次操作机会,且必须全部用完,每次操作可以选择一个下标i,使得s[i]保持不变,其它的全部取反,求k次操作机会所能构造的按字典序排序的最大二进制串。

思路:贪心策略就是从高位到低位,让1尽可能保持不变,让0尽量变为1,。我们可以发现,1进行奇数次翻转后变成0,0进行奇数次翻转后会变成1,偶数次则不变,所有当k为奇数时,对于1在k不减为0的情况下,要对它操作奇数次,这里选择最少的次数1次,这样它就会翻转(奇数-奇数=偶数)次从而保持不变,0就不需要操作,进行奇数次翻转自然会取反变为1,遍历到最后一位时,如果有k剩余,那么就对最后一位操作k次即可。k为偶数时同理。

AC code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
int n,k,a[N];
string s;
void solve(){
    cin>>n>>k>>s;
    for(int i=1;i<=n;i++) a[i]=0;
    s='!'+s;
    if(k&1){
        for(int i=1;i<n;i++){
            if(s[i]=='1'){
                if(k){
                    a[i]++;
                    k--;
                }else{
                    s[i]='0';
                }
            }else if(s[i]=='0'){
                s[i]='1';
            }
        }
        if(s[n]=='1'){
            if(k%2==0){
                s[n]='0';
            }
        }else{
            if(k%2==0){
                s[n]='1';
            }
        }
        a[n]=k;
    }else{
        for(int i=1;i<n;i++){
            if(s[i]=='0'){
                if(k){
                    s[i]='1';
                    a[i]++;
                    k--;
                }
            }
        }
        if(s[n]=='1'){
            if(k&1){
                s[n]='0';
            }
        }else{
            if(k&1){
                s[n]='1';
            }
        }
        a[n]=k;
    }
    for(int i=1;i<=n;i++){
            cout<<s[i];
        }
        cout<<endl;
        for(int i=1;i<=n;i++){
            cout<<a[i]<<' ';
        }
        cout<<endl;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

C. Line Empire

题目链接:Problem - C - Codeforces

题意:给定n个城市的位置(位置均大于0)且依次增大,一开始有一个首都位于0号点,然后我们每次可以花费a⋅|c1−c2|的代价进行迁都,其中c1是当前首都位置,c2是要迁都到的位置,a是一个迁都代价系数,前提是c2这个城市已经被占领了。我们还可以花费b⋅|c1−c2|占领位于c2位置的城市,但是不改变首都的位置,而且c1和c2之间不能有未被占领的城市(只能一个一个攻克),其中c1是首都的位置。问我们占领所有的城市所需要的最小代价。

思路:攻打第一个城市肯定不能迁移,直接攻克就好,而对于后面的城市,是选择移动到该城市的前一个城市再攻打呢?还是选择直接攻打?假设当前的首都位置为pos,对于第一种情况的代价是a*abs|c[i-1]-pos|+b*|c[i-1]-c[i]|,第二种情况的代价是b*|c[i]-pos|,很容易就想比较两者取最小值判断是否迁移,但是我们眼光要长远,假设我们后面还要占领j个城市,那么我们就要重复的花费j*b*|c[i-1]-pos|代价,这是不迁移所带来的的额外的代价,因此即使第一种情况的代价>第二种情况的代价,我们还需要将它们的差值与重复的花费代价进行比较,详情见代码。

AC code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
ll n,a,b,x[N];
void solve(){
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++) cin>>x[i];

    ll ans=x[1]*b;
    ll pos=0;
    ll cnt=n-2;
    for(int i=2;i<=n;i++){
        ll t=a*abs(x[i-1]-pos)+b*abs(x[i]-x[i-1]);
        ll tt=b*abs(x[i]-pos);
        if(t<=tt){
            pos=x[i-1];
            ans+=t;
        }else if(t>tt && cnt*b*abs(x[i-1]-pos)>=t-tt){
            cnt--;
            pos=x[i-1];
            ans+=t;
        }else{
            ans+=tt;
        }
    }
    cout<<ans<<endl;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值