BZOJ4385 [POI2015]Wilcze doły

187 篇文章 0 订阅
79 篇文章 0 订阅

标签:单调队列

题目

题目传送门

Description

给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0。

请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。

Input

第一行包含三个整数 n,p,d(1dn20000000p1016) n , p , d ( 1 ≤ d ≤ n ≤ 2000000 , 0 ≤ p ≤ 10 16 )

第二行包含n个正整数,依次表示序列中每个数 w[i](1w[i]109) w [ i ] ( 1 ≤ w [ i ] ≤ 10 9 )

Output

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

Sample Input

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

Sample Output

5

HINT

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

分析

“有的选手水平不行,所以只能省选前来刷水题了。”

贪心性质的结论:一定会删掉d个数

之后单调队列扫一遍结束

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
    ll f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//**********head by yjjr**********
const int maxn=2e6+6;
int n,d,a[maxn];ll s[maxn],f[maxn],que[maxn<<2],p;
int main()
{
    n=read(),p=read(),d=read();
    rep(i,1,n)a[i]=read(),s[i]=s[i-1]+a[i];
    rep(i,0,n)f[i]=s[min(n,i+d)]-s[i];
    int head=1,tail=1,now=0,ans=d;que[1]=0;
    rep(i,d+1,n){
        while(head<=tail&&f[que[tail]]<f[i-d])tail--;
        que[++tail]=i-d;
        while(now<i-d&&s[now]+f[que[head]]<s[i]-p){
            now++;
            if(now>que[head])head++;
        }
        ans=max(ans,i-now);
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值