【Codeforces 1461E】Water Level
题目链接
翻译
让你维持水位始终在 [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;
}