1. 程式人生 > 其它 >CF1384B Koa and the Beach

CF1384B Koa and the Beach

CF1384B Koa and the Beach

https://codeforces.com/problemset/problem/1384/B1

題目大意

有點長,可以在luogu找到中文題面CF1384B1 Koa and the Beach (Easy Version) - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

解題思路

一開始的思路是整一個線段樹,從1-n迴圈遍歷進行dp。轉移思路就是,對於每一個位置找出可行的區間時間,然後查詢和上一個位置的區間是否相鄰。這兩個操作可以用線段樹來做。然而寫完線段樹才發現這個思路並不嚴謹,繼續一思考才發現根本不用線段樹。

這道題可以直接貪心地進行考慮,對於開始位置,我們要想讓當前時刻地海浪儘可能高,這樣後面地海浪會先降低再升高,用通俗地話來講,就是留夠足夠地“餘裕”。所以開始浪高我們能直接算出,為min(k, l - d[1])

,往後走的過程中,我們使海浪繼續隨走動時間變化。這時候有兩種特殊情況需要考慮。

① 如果這一步繼續走,下一步會被淹沒。

這種情況下,我們需要繼續等待海浪降低,直到可以向前走,計算出值直接賦值。

如果當前的海浪正在上升,或者計算髮現無論怎麼等都無法滿足,則輸出-1

②如果海浪就算高到k也不會淹沒。

那就一致等待直到海浪高為k,在程式上寫作講海浪位置賦值k。

原理和第一步的思路一樣,為後面的路程留夠足夠地“餘裕”。這樣貪心就一定是最優的。

於是這道題就簡單地做完啦!

因為時間複雜度是\(O(n)\),所以這個思路兩個版本都可以通過!

程式碼

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

const int maxn = 2e2;
int       n;
int       k, l;

int d[maxn + 10];


void solve()
{
    cin >> n >> k >> l;
    for (int i = 1; i <= n; i++)
        cin >> d[i];
    if (d[1] > l) {
        cout << "No\n";
        return;
    }
    int pos = min(k, l - d[1]);
    int f = 1;
    for (int i = 2; i <= n; i++) {
        if (f)
            pos--;
        else
            pos++;
        if (pos == -1 && f == 1) {
            f = 0;
            pos = 1;
        }
        if (pos + d[i] > l) {
            if (f && l >= d[i]) {
                pos = l - d[i];
            }
            else {
                cout << "No\n";
                return;
            }
        }
        if (d[i] + k <= l) {
            pos = k;
            f = 1;
        }
    }
    cout << "Yes\n";
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}