1. 程式人生 > 實用技巧 >[CF1384B2] Koa and the Beach (Hard Version) - 貪心

[CF1384B2] Koa and the Beach (Hard Version) - 貪心

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();
}