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

EagleEyeKestrel發表於2020-12-12

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;
}

相關文章