1. 程式人生 > 其它 >【Codeforces 1461E】Water Level

【Codeforces 1461E】Water Level

技術標籤:資料結構leetcode演算法佇列python

題目連結

連結

翻譯

讓你維持水位始終在 [l,r] 這個範圍

且,你每天開始的時候可以加(所以也可以不加) \(y\) 升水,然後結束的時候會少掉 \(x\) 升水(固定)。

一開始水位是 \(k\),問你這樣(水位始終在 [l,r] 這個區間) 能否持續 \(t\) 天。

題解

如果 \(y<x\),那麼顯然水位只會一直下降。則一開始如果水位大於 \(r-y\) 那麼就每次只減少 \(x\)。到了 \(r-y\) 以後,每次能增加 \(y\) 了。

則每次減少 \(x-y\)。模擬一下就好,注意如果一直減 \(x\)

出現了要減到 \(l\) 以下才能到 \(r-y\) 以下的話,那麼最後向上取整的天數要刪掉。因為不能到那一天了。。

嗯。。現在跟你說這些你又怎麼會懂呢,自己寫程式碼試試(WA一下)就知道了hhh

如果 \(y>=x\), 那麼一個比較機智的方法就是,一直減 \(x\) 減到 \(k-x*((k-l)/x)\) 即左邊界的邊緣。然後再加一次 \(y\),然後再減 \(x\) 減到

邊緣。這樣是不是沒有止境了呢? 不是的,因為你每次減到邊緣之後,水位其實就是 \(l+(k-l+times*y)\%x\), 這裡的 \(times\) 就是你每次加一次 \(y\) 總共加的

次數。這顯然是有迴圈節的,而 \(x\)

的最大值才 \(10^6\),那麼就是一個 \(\mathcal{O(N)}\) 的演算法啦。

出現了迴圈節就直接輸出 \(Yes\) 就好。

程式碼

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int X = 1e6;

vector<int> ans;
LL k,l,r,t,x,y;
bool bo[X+10];

void _judge(LL days){
    if (days >= t){
        cout << "Yes" << endl;
    }else{
        cout << "No" << endl;
    }
}

int main(){
    // freopen("C://1.cppSourceProgram//rush.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0);
    //1 input data
    cin >> k >> l >> r >> t >> x >> y;
    //2 y < x continue subtraction
    if (y < x){
        LL t0 = 0;
        //3 sub x first until that k+y <= r ie. k<=r-y
        //
        if (k>r-y){
            //4 r-y < l no add just go die
            if (r - y < l){
                t0 = (k-l)/x;
                _judge(t0);
                return 0;
            }else{
                //5 r - y >= l, cal first t0 days to let k <=r-y
                t0 = (k-(r-y)-1)/x+1;
                k -= t0*x;
            }
        }
        //k <= r-y
        //6 k < l ->output t0
        if (k < l){
            //最後一天不能加上
            t0--;
            _judge(t0);
            return 0;
        }
        //7 l <= k <= r-y
        //add y  sub  x  and  x > y
        LL t1 = (k-l)/(x-y);
        _judge(t0+t1);
    }else{
        // y >= x
        //8 增加的比減少的多
        //減到不能減為止,然後開始加。再減到不能減為止,再加一次。直到出現迴圈,或者超出界限。
        // 9 先減到不能減為止
        LL t0 = 0;
        t0 += (k-l)/x;
        k -= t0*x;
        // 10 令 delta = k-l
        LL delta = k - l;
        // 開始讓這個數加 y 然後對 x 取模(對應再減到不能減)。直到出現重複為止。
        bo[delta] = true;
        delta = delta+y;
        while (delta <= r-l){
            t0 += delta/x;
            if (t0>=t){
                break;
            }
            delta = delta%x;
            if (bo[delta]){
                t0 = t;
                break;
            }
            bo[delta] = true;
            delta = delta + y;
        }
        _judge(t0);
    }
    return 0;
}