1. 程式人生 > 其它 >Luogu P3594 [POI2015]WIL-Wilcze doły(單調佇列)

Luogu P3594 [POI2015]WIL-Wilcze doły(單調佇列)

傳送門

題面:

題解:

首先我們要發現,假如右端點為\(i\) ,能到達的最遠的左端點為 \(j\) 時,那麼 右端點為 \(i+1\) 時,能到達的最遠左端點一定大於等於 \(j\) 。為什麼?假設存在這種情況,因為\(i+1\)\(i\) 多了一個 \(a[i+1]\) ,那麼說明 \(i\) 的最長區間的和比 \(i+1\)小,而\(i+1\) 能到達一個更小的位置,那麼說明 \(i\) 也能到達那個位置,與假設衝突。

知道上述結論後,我們假設 \(i\) 能到達的最遠左端點為 \(last\) ,那麼我們去看 \([last,i+1]\)是否滿足條件,若不滿足,則\(last\)

​ 往右移動,直至滿足為止。一直重複上述過程即可。

如何看是否滿足呢?即區間和減去長度為\(d\)的最大區間和是否\(<\) p。 那麼就得維護最大的長度為\(d\) 的區間和。利用單調佇列即可。

程式碼:

#pragma GCC diagnostic error "-std=c++11"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int MAXN = 2e6 + 5;
const int inf = 0x3f3f3f3f;
int q[MAXN];
ll a[MAXN],pre[MAXN],sum[MAXN];
int main()
{
    int n, d;
    ll  p;
    cin >> n >> p >> d;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        pre[i] = pre[i - 1] + a[i];
    }
    int l = 0, r = 0;
    int ans = d;
    for (int i = d; i <= n;i++){
        sum[i] = pre[i] - pre[i - d];
    }
    q[l] = d;
    int last = 1;
    for (int i = d + 1; i <= n;i++)
    {
        while(l<=r&&sum[i]>sum[q[r]])
            r--;
        while(l<=r&&q[l]-d+1<last)
            l++;
        q[++r] = i;
        while(pre[i]-pre[last-1]-sum[q[l]]>p)
        {
            last++;
            while (l <= r && q[l] - d + 1 < last)
                l++;
        }
        ans = max(ans, i - last + 1);
    }
    cout << ans << endl;
}