654 div2 problemC. A Cookie for You题解(数学 + 思维 + 模拟)

传送门

题意

  • 有 a 个 饼干,和 b 个巧克力
  • 有 n 个 第一类人,有 m 个第二类人
    • 对于第一类人, if (a > b)吃一个饼干,else 吃一个巧克力
    • 对于第二类人, if (a > b)吃一个巧克力,else 吃一个饼干
  • 问你是否有一种方法能让第一类和第二类人都有东西吃,有输出Yes,否则输出No

思考

  • 很显然第一类人优先吃多的(一样多就吃巧克力),第二类人优先吃少的(一样多就吃饼干)
  • 有两种思路,一个是我自己比赛时想到的,一个是x大佬讲的
  • 方法一
    • 一来就判断饼干和巧克力的总数够不够第一类和第二类人吃,如果不够,直接No,如果够如下
    • 先让第二类人吃,方便我们思考,因为东西只会被越吃越少嘛,不可能越吃越多,所以他自始至终都会不会换别的吃
    • 然后就是判断最少的是否够第二类人吃。先讨论最简单的——够,显然如果够的话则第一类人一定够吃,为什么,因为第一类人是优先吃最多的,而我们先判断的是总数都够吃,所以无论怎么吃,不管最多的东西怎么变化,都是够吃的,所以是Yes;
    • 但是如果不够吃呢,直接就是No,为什么,解释起来有点麻烦(比赛时候我就是这里没有想好,一直往别的地方想,自己扰乱了自己的思维)。先这样想,如果不够吃,那么最小的永远都是那一个(饼干或者巧克力一开始最少的):因为不够吃,所以那一个就会被吃完(即等于0),但是呢第二类人还有没吃到的,他们只会吃最少的那一个,而最少的那一个个数是0了,所以无论如何都吃不了了。
    • 比赛的时候我往别的地方想了(相信不止我会这样想歪,现在想通了,解释一下,可能会有点啰嗦):就是如果最少的不够第二类人吃的话那就一开始先让第一类人吃,或者中途到了某个关系后交替来吃。但是这样只会让自己陷入窘境,其实这种情况下,无论是让第一类人先吃,还是交替吃,都不会改变第二类人没得吃的结果。因为第一类人的插入只会让最多数量的那个东西变少,一直吃到饼干和巧克力个数一样时,最少的个数依然是最少,即便最少的种类可能会变,但是第二类人能吃的个数不会变。换句话说就是,即便它最少或最多的种类转移了,第二类依然会吃最少的,他不可能可以多吃一个多的那一个(即便饼干和巧克力相等)
    • 详细见代码solve()函数
  • 方法二
    • 第一步和方法一相同,总数不够就No,否则如下
    • 利用一个小规律:先让第二类人吃一次,再让第一类人吃一次,这样的话无论两者大小,饼干数和巧克力数都会各自减一。利用这个特点把人和东西给简化。
    • 第一种可能,东西(饼干或者巧克力)优先有一方优先减到0,而两类人都还有,那么一定是No,因为第二类人只吃最少的,而最少的为0了
    • 第二种可能就是,人优先有一方减到了0,这时候如果是第二类人减到了0,显然就是Yes(道理和方法一中最少数量的东西够第一类人吃是一样的)。如果是第一类人减到了0,那么也就是说只剩下第二类人,因为第二类人只吃最少的,所以只要判断最少的那个东西够不够第二类人吃就行了,够就Yes,不够就No
    • 详细见代码solve2()函数
  • 代码如下
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<long long> vll;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
#define debug printf("(hao)")
#define all(x) x.begin(), x.end()
#define rep(i, a, b) for (int i = (a); i < (b); i++)
#define clr(a, v) memset(a, v, sizeof(a))

void solve() {//方法一
    // int n;
    ll a, b, n, m;
    scanf("%lld%lld%lld%lld", &a, &b, &n, &m);
    if (a + b < n + m) printf("No\n");  //判断总数够不够吃,不够吃就No
    else {
        ll Min = min(a, b);             //寻找最小的一堆食物
        if (Min >= m) printf("Yes\n"); // 最少的够第二类人吃
        else printf("No\n");            //最少的不够第二类人吃
    }
}
void solve2() {//方法二
    // int n;
    ll a, b, n, m;
    scanf("%lld%lld%lld%lld", &a, &b, &n, &m);
    if (a + b < n + m) printf("No\n");
    else {
        ll temp = min(n, m), tmin = min(a, b);
        if (tmin >= temp) {                 //如果人先出现0,即第二种可能
            a -= temp, b -= temp, n -= temp, m -= temp;//全部均掉简化
            if (m == 0) printf("Yes\n");//第二类人为0
            else {                      //还有第二类人剩下
                if (min(a, b) >= m) printf("Yes\n");
                else printf("No\n");
            }
        } else printf("No\n"); //食物先出现0,即上述第一种可能
    }
}

// #define LOCAL
int main() {
    std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while (T--) {
        solve();
        // solve2();
    }
    return 0;
}

反思

  • 在比赛的时候想到了方法一,但是没有认真用代码实现,并且在往深处思考的时候反而被别个可能性干扰了,也没能及时想出方法反驳自己,而是冒出让第一类人先吃的想法解决自己的矛盾,并没有想到就算第一类人吃了耶挽回不了第二类人的命运(没得吃)
  • 感觉自己当时思维会混乱极有可能就是比赛的状态,打得少,做得少
  • 想到方法就往一处想,尽量不要再想别的,或者想到别的发现想不下去就回到之前的状态重新换方向想

总结

  • 模拟就是要看题量如何
  • 思维的严谨和正确性都是题量堆积出来的,经验的多少决定(十分影响)了思维的快慢和正误
  • 所以做刷题,多打比赛,多总结

原地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值