CF 779 C Dishonest Sellers 贪心,排序

题目链接:见这里
题意:给了一些物品,每个物品有俩个价格,一个是打折前的,一个是打折后的(打折发生在一周后),现在一个人必须先买k个物品,然后剩下的物品既可以选择现在买,也可以选择一周后买,其中打折后的价格不一定比现有价格低,无良商人,大家都懂。
解法:我们先考虑一下必须买的k个物品,肯定要优先选择那些打折后变贵的物品,并且在变得同等贵的时候,我们要优先买现在价格大的。买完k个之后,剩下的就是俩个价格取个小,这题就做完了。

//CF 779C
#include <bits/stdc++.h>
using namespace std;
struct node{
    int x, y;
    node(){}
}a[200010];
bool cmp(node a, node b){
    if((a.x - a.y) == (b.x - b.y)){
        return a.y > b.y;
    }
    return (a.x - a.y) < (b.x - b.y);
}
int n, k;
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i].x);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i].y);
    sort(a + 1, a + n + 1, cmp);
    int ans = 0;
    for(int i = 1; i <= n; i++){
        if(i <= k) ans += a[i].x;
        else ans += min(a[i].x, a[i].y);
    }
    printf("%d\n", ans);
    return 0;
}
<think> 根据问题描述,我们需要编写一个C语言程序来判断Tom在猜数字游戏中是否作弊。游戏规则如下: - 数字范围为1到10。 - Jerry每次猜一个数字,Tom的回答是"too high"、"too low"或"right on"。 - 当回答为"right on"时,该轮游戏结束。 - 输入以Jerry猜0结束(表示整个输入结束)。 判断作弊的逻辑: 1. 维护两个变量:`min`和`max`,分别表示当可能的最小值和最大值(初始时`min=1`,`max=10`)。 2. 对于每次猜测: - 如果Tom回答"too low",则更新`min`为当猜测值+1(因为实际数字应该比这个猜测值大),但注意不能超过当`max`,如果更新后`min>max`,则出现矛盾。 - 如果Tom回答"too high",则更新`max`为当猜测值-1(因为实际数字应该比这个猜测值小),同样不能低于当`min`,如果更新后`min>max`,则出现矛盾。 - 如果Tom回答"right on",则检查最终猜的数字是否在`[min, max]`范围内。如果在,则说明没有矛盾;否则,Tom作弊。 3. 注意:在每一轮游戏结束后,需要重置`min`和`max`(重置为初始值1和10)。 4. 另外,如果在一轮游戏过程中,某次更新后出现`min>max`,那么即使还没有到"right on",也可以判定作弊。但是,题目要求是记录整个游戏过程,直到"right on"才结束一轮,所以我们需要等到出现"right on"时再输出结果。然而,在出现矛盾后,即使后面还有猜测,我们也可以提知道Tom作弊,但要注意后续的记录可能还有,所以我们在出现矛盾后可以记录一个标志,等到"right on"时输出作弊即可。 但是,注意题目输入是连续的,每轮游戏由多次猜测组成,直到出现"right on"结束一轮。然后下一轮开始,直到输入0为止。 根据提供的样例代码,它是在遇到"right on"时才判断作弊,并且重置范围。但是,在过程中如果出现了矛盾(比如更新后最小值大于最大值),那么即使后面还没有到"right on",实际上已经可以确定作弊。然而,输入是连续的,我们必须在出现"right on"时才输出结果。所以我们需要在过程中记录是否出现过矛盾。 改进思路: - 在每一轮游戏中,我们用一个标志变量`honest`(初始为1,表示诚实)来记录是否出现矛盾。 - 对于每一次猜测: - 如果回答是"too low",则更新`min`,然后检查如果`min>max`,则设置`honest=0`(表示出现矛盾,Tom作弊)。 - 如果回答是"too high",则更新`max`,然后检查如果`min>max`,则设置`honest=0`。 - 如果回答是"right on",则除了检查范围(最终猜测值是否在`[min, max]`)外,还要检查`honest`是否为1(即过程中没有矛盾)。如果最终猜测值不在`[min, max]`,或者过程中已经出现矛盾,则判定Tom作弊。 然而,注意:在更新`min`和`max`时,我们还要注意当猜测值是否在之确定的范围`[min, max]`之外?比如,如果当猜测值比`min`还要小,而Tom却说"too low",这显然是矛盾的(因为之已经有信息表明数字至少是`min`,而这次猜的比`min`还小,却被告知太低,不合理)。同样,如果当猜测值比`max`还要大,而Tom却说"too high",也是矛盾。 所以,我们需要在每次更新检查当猜测值与当范围的关系: - 当回答是"too low"时,如果当猜测值大于等于当`max`,那么这是矛盾的(因为实际数字最大是`max`,而猜测值已经大于等于`max`,不可能再得到"too low"的回答)。同样,如果当猜测值小于当`min`,那么这次猜测值比之确定的`min`还小,却得到"too low",说明实际数字应该比这个值大,但之已经确定实际数字至少为`min`(比当值大),所以这个猜测值应该被忽略吗?实际上,这个猜测值是不合理的,因为之的信息已经表明数字至少是`min`,而现在猜了一个比`min`还小的数,却被告知"too low",这反而进一步验证了实际数字大于这个值,但由于已经知道实际数字大于等于`min`,所以不会影响范围。但是,如果当猜测值小于`min`,那么更新`min`的操作(`min = guess+1`)可能会导致范围错误扩大?实际上,我们不应该用比当`min`还小的值来更新`min`,因为`min`已经是已知的最小可能值。 因此,更严谨的做法是: 1. 在得到回答后,先检查当猜测值是否与已有范围矛盾: - 如果回答是"too low",但当猜测值大于等于当`max`,则矛盾(因为实际数字<=`max`,而当猜测值>=`max`,说明实际数字小于等于当猜测值,不可能“太低”)。 - 同样,如果回答是"too high",但当猜测值小于等于当`min`,则矛盾(因为实际数字>=`min`,而当猜测值<=`min`,说明实际数字大于等于当猜测值,不可能“太高”)。 2. 如果没有上述矛盾,再进行范围更新,然后检查更新后范围是否有效(`min<=max`)。 所以,我们可以这样设计一轮游戏的处理: - 初始化:`min=1`, `max=10`, `honest=1`(表示没有矛盾) - 循环读取猜测值和回答(字符串): - 如果回答是"too low": - 如果`guess >= max`,那么实际数字最大为`max`,而`guess`大于等于`max`,实际数字不可能比`guess`大,所以Tom说"too low"是矛盾的(因为实际数字要么等于`guess`,要么小于`guess`,都不会导致“太低”)。此时设置`honest=0`。 - 否则,更新`min = (guess+1 > min) ? guess+1 : min`。因为如果`guess+1`比当`min`大,则更新,否则保持`min`不变(因为`min`已经比`guess+1`大了)。 - 然后检查更新后的`min`是否大于`max`,如果是则设置`honest=0`。 - 如果回答是"too high": - 如果`guess <= min`,那么实际数字至少为`min`,而`guess`小于等于`min`,实际数字不可能比`guess`小,所以Tom说"too high"矛盾。设置`honest=0`。 - 否则,更新`max = (guess-1 < max) ? guess-1 : max`。 - 然后检查更新后的`max`是否小于`min`,如果是则设置`honest=0`。 - 如果回答是"right on": - 首先,检查最终猜测值是否在`[min, max]`区间内。如果不在,则`honest=0`。 - 然后,根据`honest`的值输出结果:如果`honest`为1,则输出"Tom may be honest";否则输出"Tom is dishonest"。 - 重置变量:`min=1`, `max=10`(为下一轮准备),并跳出本轮循环。 但是,注意:在过程中如果已经出现矛盾(`honest=0`),我们仍然需要继续读取输入直到"right on",因为输入是连续的,不能提跳出(除非我们知道这一轮结束的标志)。所以,我们在处理每一轮时,即使出现了矛盾,也要继续读完本轮的所有输入(直到遇到"right on")。 另外,在更新范围时,我们只考虑能进一步缩小范围的情况。例如,当回答"too low"时,新的`min`应该是`max(当min, guess+1)`;当回答"too high"时,新的`max`应该是`min(当max, guess-1)`。 参考代码实现如下: </think> 以下是判断Tom在猜数字游戏中是否作弊的C语言代码实现: ```c #include <stdio.h> #include <string.h> #include <ctype.h> int main() { int guess; char response[20]; int min, max; int honest; // 1表示诚实,0表示作弊 while (1) { // 初始化每轮游戏的变量 min = 1; max = 10; honest = 1; while (1) { scanf("%d", &guess); getchar(); // 消耗换行符 if (guess == 0) return 0; // 游戏结束 // 读取Tom的回应 fgets(response, sizeof(response), stdin); response[strcspn(response, "\n")] = '\0'; // 移除换行符 // 转换为小写便于比较 for (int i = 0; response[i]; i++) { response[i] = tolower(response[i]); } // 处理回应 if (strstr(response, "high")) { // 检查"too high"是否合理 if (guess <= min) { honest = 0; // 数值已低于下限却还太高,矛盾 } else if (guess - 1 < max) { max = guess - 1; // 更新上限 } } else if (strstr(response, "low")) { // 检查"too low"是否合理 if (guess >= max) { honest = 0; // 数值已高于上限却还太低,矛盾 } else if (guess + 1 > min) { min = guess + 1; // 更新下限 } } else if (strstr(response, "right")) { // 最终检查:猜中值是否在合理范围内 if (guess < min || guess > max) { honest = 0; } break; // 结束本轮游戏 } // 检查范围是否矛盾 if (min > max) { honest = 0; } } // 输出结果 printf("%s\n", honest ? "Tom may be honest" : "Tom is dishonest"); } return 0; } ``` ### 代码说明: 1. **初始范围设置**:每轮游戏开始时,数字范围设为$[1, 10]$ 2. **回应处理逻辑**: - `too high`:更新上限 $max = \min(max, guess-1)$ - `too low`:更新下限 $min = \max(min, guess+1)$ - `right on`:检查$guess$是否满足 $min \leqslant guess \leqslant max$ 3. **作弊检测**: - 最终猜测值超出范围 $[min, max]$ - 更新后范围矛盾 $min > max$ - 数值已低于下限却回应"too high" - 数值已高于上限却回应"too low" 4. **输入处理**: - 使用`fgets`读取回应,避免缓冲区溢出 - 转换为小写增强鲁棒性 - 输入0时程序终止 ### 输入示例: ``` 5 too low 7 too high 6 right on 10 too high 3 too low 4 too high 2 right on 0 ``` ### 输出示例: ``` Tom may be honest Tom is dishonest ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值