bzoj 4385 poi 2015 Wilcze doły 单调队列

10319: Wilcze doły

时间限制: 1 Sec  内存限制: 128 MB
提交: 69  解决: 24
[提交] [状态] [讨论版] [命题人:admin]

题目描述

给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0。
请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。

输入

第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16)。
第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9)。

输出

包含一行一个正整数,即修改后能找到的最长的符合条件的区间的长度。

样例输入

复制样例数据

9 7 2
3 4 1 9 4 1 7 1 3

样例输出

5

提示

将第4个和第5个数修改为0,然后可以选出区间[2,6],总和为4+1+0+0+1=6。

来源/分类

POI2015 

[提交] [状态]

题意让选出最长的一段连续区间使得该区间内数的和不超过p,条件是可以把一段长度不超过d的连续区间里的数字全部修改为0

第一眼看到,没思路,后来想了想因为数据2e6,只能O(n),又因为要维护区间的最大值,所以想到单调队列

但是因为以前接触的单调队列都是确定长度的滑动区间,这个找最长就有点懵,觉得自己思路可能错了

后来上网搜题解,看到确实是单调队列,然后发现思路有点问题

单调队列维护的是d长度的最大区间,所以长度是已知,求最长长度的问题就可以囊括在里面

假设区间i到j之间是维护的该区间,那么该区间的和减去区间内d长度的和之后大于p,说明该区间不可行,那么左端点i+1

说的貌似有点乱,但是思路是单调队列没错的

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+100;
ll s[maxn];
ll f[maxn];
int in[maxn];
int main(){
    int n,d;
    ll p,a;
    scanf("%d%lld%d",&n,&p,&d);
    for(int i=1; i<=n; i++){
        scanf("%lld",&a);
        s[i]=s[i-1]+a;
    }
    for(int i=d; i<=n; i++){
        f[i]=s[i]-s[i-d];
    }
    int tail=0,head=0;
    int ans=d,i=0;
    for(int j=d; j<=n; j++){
        while(head<=tail && f[j]>=f[in[tail]])  tail--;
        in[++tail]=j;
        while(s[j]-s[i]-f[in[head]]>p){
            i++;
            while(head<=tail && in[head]-d<i) head++;
        }
        ans=max(ans,j-i);
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/renzijing/article/details/84984262
今日推荐