Codeforces Round 689(Div.2) E题 Water Level

CF Round 689(Div2) Water Level

In recent years John has very successfully settled at his new job at the office. But John doesn’t like to idly sit around while his code is compiling, so he immediately found himself an interesting distraction. The point of his distraction was to maintain a water level in the water cooler used by other zebras.

Originally the cooler contained exactly 𝑘 liters of water. John decided that the amount of water must always be at least 𝑙 liters of water but no more than 𝑟 liters. John will stay at the office for exactly 𝑡 days. He knows that each day exactly 𝑥 liters of water will be used by his colleagues. At the beginning of each day he can add exactly 𝑦 liters of water to the cooler, but at any point in time the amount of water in the cooler must be in the range [𝑙,𝑟].

Now John wants to find out whether he will be able to maintain the water level at the necessary level for 𝑡 days. Help him answer this question!

Input

The first line of the input contains six integers 𝑘, 𝑙, 𝑟, 𝑡, 𝑥 and 𝑦 ( 1 ≤ l ≤ k ≤ r ≤ 1 0 18 , 1 ≤ t ≤ 1 0 18 , 1 ≤ x ≤ 1 0 6 , 1 ≤ y ≤ 1 0 18 ) (1\leq l\leq k\leq r\leq 10^{18}, 1\leq t≤10^{18}, 1\leq x\leq 10^6, 1\leq y\leq 10^{18}) (1lkr1018,1t1018,1x106,1y1018) — initial water level, the required range, the number of days, daily water usage and the exact amount of water that can be added, respectively.

Output

Print “Yes” if John can maintain the water level for 𝑡 days and “No” otherwise.

Examples

Example 1:

Input: 8 1 10 2 6 4
Output: No

Example 2:

Input: 8 1 10 2 6 5
Output: Yes

Example 3:

Input: 9 1 10 9 2 9
Output: No

Example 4:

Input: 20 15 25 3 5 7
Output: Yes

题目理解起来没什么难度。六个数字的意思是,最开始有k的水,水的范围始终要在[l,r]内。要熬过t天,每天别人要用掉x,每天开始的时候自己可以加y的水,要么加y要么不加。问能否熬过t天?

本来是简单的模拟,但注意到数据范围都很大,遍历一遍也不行。除了x都很大,可能会从x入手解决一些问题。其实这种题知道最后要么是达到了t,要么是最后进入一种水量循环的状态,就说明可以熬过。当时想的就是暴力讨论,但觉得好烦直接放弃了。。其实看了答案发现,完全是可以做的,应该耐心地写一写。

代码借鉴自官方题解:

  • 先直接排除k不在范围内
  • x > y 先讨论,其实我当时也是这么想的。。但居然放弃了。x > y说明此后水量一定是衰减的,所以肯定能加尽量加水。先判断一下第一天加不加,然后看看能撑几天。
  • x <= y 略复杂,因为通过一次加水可以使得水量变多。用个哈希表记一下已经到达过的k状态。这里的策略是,先不加水,用到最少之后再加(因为如果前一天没加水熬过了,今天如果可以加水,就一定能够熬过,这样可以控制尽量不超过上界r)。然后就让水减到最少(不能再少或者时间结束),接下来一天,能加水就加水。如此循环往复。
  • 关于复杂度,可以发现循环的时候,k的剩余量其实是和不断减去x的余数有关,所以和x较小的范围是一致的。
  • 哎自己的思路其实都是对的,应该坚持一下,当时还剩了挺多时间。看到没多少人做出来,就直接放弃了,以后不能这样。
#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<unordered_set>
using namespace std;
long long l, k, r, t, x, y;
unordered_set<long long> s;
int main()
{
    cin >> k >> l >> r >> t >> x >> y;
    if (k < l || k > r) {
        cout << "No\n";
        return 0;
    }
    if (x > y) {
        if (k + y > r) {
            k -= x;
            t--;
        }
        if (k < l) {
            cout << "No\n";
            return 0;
        }
        long long canAlive = (k - l) / (x - y);
        cout << (canAlive < t ? "No\n" : "Yes\n");
    } else {
        s.clear();
        while(t > 0) {
            if (s.count(k)) {
                cout << "Yes\n";
                return 0;
            }
            s.insert(k);
            long long canMove = min(t, (k - l) / x);
            k -= canMove * x;
            t -= canMove;
            if (t == 0) {
                cout << "Yes\n";
                return 0;
            }
            t--;
            if (k + y <= r) k += y;
            k -= x;
            if (k < l || k > r) {
                cout << "No\n";
                return 0;
            }
        }
        cout << "Yes\n";
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值