题目链接: Water Level
大致题意
有一个饮水机, 里面有k升水, 每天早上你可以像里面添加y升水, 每天晚上饮水机会被喝掉x升水.
问: 是否能在t天内, 使得饮水机的容量一直处于[l, r].
解题思路
首先这个题先进性一下左边界化简, 只需要让 k和r 都减去l即可. 之后都只需要考虑水的容量是否会大于r即可
此问题我们可以分类讨论:
①如果 x == y, 那么每天的加水和喝水量是相同的, 因此只需要判断第一天能否加水, 以及能否喝到水即可. 往后的天数都会进行循环.
②如果x > y 说明供不应求, 我们应该尽可能多的往里面进行加水操作. 而每天消耗的水应该是**(x - y)升**. 那么能坚持的天数day = k / (x - y) .
需要注意的是: 如果我们以这样方式计算出来的day, 实际上是把加水和喝水同步进行了, 而题目中其实是先加再喝, 由于 x > y, 因此有加水量 < 喝水量, 因此除了第一天的情况, 之后的每一天喝完了都一定是可以再加的, 相当于喝水和加水同步进行了, 因此特殊判断第一天是否能加水的情况即可.
③如果x < y, 说明此时我的加水量 > 喝水量, 因此我每天加了水后, 一定够喝. 所以不妨我们就等到晚上水不够喝的时候再去加水(这样可以让(r - 当前水容量) 尽可能大, 更好满足条件.) 此时假设水容量为k(k < x), 然后我给饮水机加水, 使得水容量变为(k + y). 如此反复, 当我们出现一个k’ == k, 此时则会形成一个水容量的循环. 因为x ∈ [1, 1E6], 因此这个循环最多会执行x次.
那么这种情况下:
有两种情况可以满足要求: 计算结果可以满足坚持t天, 水容量出现了循环.
有一种情况不满足要求: 当水容量为k(k < x), 此时 k + y > r.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define debug(a) cout << #a << " = " << a << endl;
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
bool vis[N];
int main()
{
ll k, l, r, t, x, y; cin >> k >> l >> r >> t >> x >> y;
r -= l, k -= l;
if (x == y) {
if (k + y <= r) k += y;
printf("%s\n", k >= x ? "Yes" : "No");
}
else if (x >= y) { //用得多
if (k + y <= r) k += y;
k -= x;
ll cha = x - y;
ll day = k / cha;
printf("%s\n", day + 1 >= t ? "Yes" : "No");
}
else {
do {
ll day = k / x;
k -= day * x, t -= min(t, day);
if (vis[k]) break;
vis[k] = 1;
k += y;
if (t && k > r) printf("No\n"), exit(0);
} while(t);
printf("Yes\n");
}
return 0;
}