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

 
                
             
         浙公网安备 33010602011771号
浙公网安备 33010602011771号