Description

考虑 \([0,n+1]\) 之间的所有整点,你要从 \(0\) 走到 \(n+1\),每秒钟可以从 \(x\) 走到 \(x+1\) 或者不动。每个位置有一个高度 \(h_i\),每个时刻有一个高度 \(p_t\)(在 \([0,k]\) 之间均匀循环,\(0,1,...,k-1,k,k-1,...,1,0,...\))。如果 \(h_i+p_t>l\) 则失败。问是否能走到 \(n+1\)

Solution

如果一个点永远是安全的,那么就称它为安全点。在每个安全点,我们可以暴力等到任何一个时刻再往后走,因此整个过程被安全点分成了若干段,我们只需要考虑相邻两个安全点之间的点。

我们考虑当前即将走到位置 \(i\) 并且当前的浪高为 \(tide\),如果 \(dep_i+tide>l\) 那么显然我们需要等待 \(\Delta=dep_i+tide-l\) 的时间让浪潮接着下降,于是令 \(tide \leftarrow tide-\Delta\),若 \(<0\) 则非法。

这里关键是这种方案的结论对于非法性来说为什么是必要的。因为在上一个安全点之后,我们处理的所有点都不能碰到最高了那个位置,所以本质上一些连续的非安全点必须要在一个浪潮来回的过程中被处理完。

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

#define int long long 
const int N = 1000005;

int T,n,k,l,dep,tide,fg;

void solve()
{
    cin>>n>>k>>l;
    tide=k;
    fg=0;
    for(int i=1;i<=n;i++)
    {
        cin>>dep;
        if(dep+k>l)
        {
            if(fg==0) tide--;
            else tide++;
            if(fg==0) tide=min(tide,l-dep);
            if(tide==0) fg=1;
            if(tide<0 || tide>l-dep) 
            {
                puts("No");
                while(i<n) cin>>dep, ++i;
                return;
            }
        }
        else
        {
            tide=k;
            fg=0;
        }
    }
    puts("Yes");
}

signed main()
{
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--) solve();
}

相关文章: