题意:沙滩从左往右由海岸线,n米的海和一个在n+1的点的岛组成。一个人测量了从海岸线(1,2,dots,n)米到岛屿的海的深度,并保存在(d)数组中,这个海有潮汐,潮汐的强度取决于参数(k),参数(k)影响了海的深度,对于从时间(t = 0)开始,先k秒,每一秒,潮汐导致所有的深度+1,然后再k秒,潮汐每秒导致所有的深度都减1。这个过程不断地持续着,例如对于索引从0开始的数组(p = [0, 1, 2,...,k - 2, k - 1, k, k - 1, k - 2, ..., 2, 1]),长度为2k,在时间t,第i米的深度为(di+p[t\,mod\,k])。这个人从海岸线开始游到岛屿,每一秒,他可以前进或者呆在原地,时间t + 1,这个人有一个被淹死的水的深度的参数(l),如果(当且深度>l),那么这个人就会被淹死。求是否存在一种游的方式,使得这个人可以游到岛屿。
分析:贪心做法,我们考虑两个完全安全的点的状态,什么是完全安全的点呢?比如dep[i] + k <= l,就是加上潮汐的最大增量也不会超过淹死的深度的点。考虑两个完全安全点之间的点,我们思考什么样的贪心决策最好。从一个完全安全点开始,我们不错的决策是,等到潮汐上涨到最大的时候,我们才往之后的点游下去,因为之后潮汐是随着时间下降的,如果接下来的点dep[i] + tide > l的话,即加上这个随时间下降的潮汐的值都大于l的话,那么我们就没有办法,只能再等一会时间,要等多久呢,即diff = dep[i] + tide - l,相应的潮汐的下降值,tide - diff,如果tide - diff < 0,说明没有更优的方案游了,否则让tide变成tide - diff。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 300005;
int d[N];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, k, l;
scanf("%d%d%d", &n, &k, &l);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &d[i]);
}
vector<int> v;
v.push_back(0);
for (int i = 1; i <= n; ++i)
{
if (d[i] + k <= l) v.push_back(i);
}
v.push_back(n + 1);
bool flag = true;
for (int i = 1; i < v.size(); ++i)
{
bool down = true;
int tide = k;
//两个完全的安全点之间的点
for (int j = v[i - 1] + 1; j < v[i]; ++j)
{
//潮汐加上随时间变换的量
tide += down ? -1 : 1;
if (down)
{
//深度值加上潮汐增量都大于l的话,我们要等一会,让潮汐再降一些
if (d[j] + tide > l)
{
int diff = d[j] + tide - l;
tide -= diff;
}
}
if (tide < 0 || d[j] + tide > l)
{
flag = false;
break;
}
if (tide == 0)
{
down = false;
}
}
if (!flag) break;
}
if (flag)
{
puts("Yes");
}
else
{
puts("No");
}
}
return 0;
}