cf #787 Div3

本文介绍了Codeforces竞赛中的三道题目,包括动物饲料分配问题、数组单调递增优化及侦探任务。针对每道题目,分别给出了题意、解题思路和C++代码实现。通过贪心算法和逻辑推理解决实际问题,展示了解决编程竞赛问题的方法和策略。
摘要由CSDN通过智能技术生成

cf #787 Div.3

A. Food for Animals

  • 题意

​ 题目大致含义:商店有三种饲料,一种只给猫猫、一种只给狗狗、一种猫猫狗狗都可以用,它们的数量为a,b,c。猫猫数量为x,狗狗数量为y,问能否让所有猫猫狗狗都吃上一包饲料

  • 题解

​ 一眼简单贪心,分别看猫猫和狗狗够不够就好

  • 代码
#include <iostream>

using namespace std;

bool ok(int a,int b,int c,int x,int y){//因为正面情况较多,那么枚举举反面例子
    if(a<x){//看猫猫在专有饲料不够情况下
        if(a+c<x)return false;//如果所有猫能吃的饲料全给猫猫都不够吃,那不行
        c-=(x-a);//如果可以填够,那么减去被用掉的通用饲料
    }
    if(b<y)//看狗狗在专有饲料不够情况下
        if(b+c<y)return false;//如果所有狗能吃的饲料全给猫猫都不够吃,那不行

    return true;//其他情况合法
}

int main()
{
    int t;
    cin>>t;
    while (t--){
        int a,b,c,x,y;
        cin>>a>>b>>c>>x>>y;
        if(ok(a,b,c,x,y))cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

B. Make It Increasing

  • 题意

​ 给定一组数,每个数都可以进行向下除2的操作,问最少需要经过多少次操作可以使得这组数严格单调递增

  • 题解

​ 一眼贪心,操作只能把数变小但要求数列单增,那么从后向前看,最后一个数必然不用去操作了,向前走一旦这个数比后一个数大就操作它减小,这样操作一定是最优解。为什么这是最优解呢?要把这组数变成递增有n种方案,每一种方案中都是最后一个数最大,那么在这n种方案中如果这种方案的最后一个数最大那么它前面数所操作的次数最少,故当最后一个数不操作时操作次数最少。

  • 代码
#include <iostream>

using namespace std;

const int N=35;

long long f(int n,int a[]){
    if(n==1)return 0;//1个数不用操作

    long long res=0;
    for(int i=n-2;i>=0;--i){//从后往前遍历操作
        while (a[i]>=a[i+1]){//如果这个数大于后一个数,需要操作
            if(!a[i])return -1;//如果这个数为0,那么再也没办法使它变小了,故无解
            a[i]/=2;//除2
            res++;//次数++
        }
    }

    return res;
}

int main()
{
    int t;
    cin>>t;
    while (t--){
        int n,a[N];
        cin>>n;
        for (int i = 0; i < n; ++i) cin>>a[i];
        cout<<f(n,a)<<endl;
    }
    return 0;
}

C. Detective Task

  • 题意

    大致题意:给定一个只含有01?三种字符的字符串,表示一列一次进画室的人的回答,0代表没看到画,1表示看到了画,?表示不记得了。其中只有那一个偷画人可以说谎,其他人必须说真话,找出嫌疑人的个数

  • 题解

    通过样例得到了一个规律:从第一个0开始向前走遇到的第一个1之间所包含的字符数就是嫌疑人数。同时10的转换只会出现一次

    简略证明:

    1 1 10 0 0

    这组字符中,第一个出现的0和从0向前的第一个1都用下划线画出来了,分别记作p0和p1,我们证明p0之后以及p1之前不会再说谎。(反证法)

    首先有个前提就是找到了这个10转换那么0之后全是0,1之前全是1。假设加粗的0是嫌疑人说谎,也就是说加粗位置是1画存在,同时之前的人全是真话,那么下划线0位置是真话,画是不存在的,换言之这幅画在之前消失了,矛盾,假设不成立,故加粗位置不可能是嫌疑人。即p0之后的人不是嫌疑人

    同理,p1前的人不可能是嫌疑人。

    那么只有p1和p0之间的人可能是嫌疑人,故答案是p0-p1+1

  • 代码

#include <iostream>
#include <vector>

using namespace std;

int f(string &s){
    int pos_last_0=s.size()-1,pos_first_1=0;//初始化,如果0不存在那么最后一位置为p0,如果1不存在那么第一个位置位置为p1
    for(int i=0;i<s.size();i++){//找p0
        if(s[i]=='0' && i<pos_last_0){
            pos_last_0=i;
            break;
        }
    }
    int i;
    for(i=pos_last_0;i>0;--i){//找p1
        if(s[i]=='1')break;
    }
    pos_first_1=i;
    return pos_last_0-pos_first_1+1;
}

int main()
{
    int t;
    cin>>t;
    while (t--){
        string s;
        cin>>s;
        cout<<f(s)<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值