BZOJ4385: [POI2015]Wilcze doły

来源:互联网 发布:淘宝彩票是真的吗 编辑:程序博客网 时间:2024/05/16 07:50

删的数肯定越多越好,所以可以删的区间有n个,枚举答案的右端点,维护一个单调队列,记录当前左端点到当前右端点里的可删区间的最大值,O(n)扫过去就行了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void read(int &x){    char c; while(!((c=getchar())>='0'&&c<='9'));    x=c-'0';    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';}const int maxn = 2100000;ll p;ll qs[maxn];int q[maxn],head,tail;int n,d,a[maxn];int ans,ni; ll re;int main(){    scanf("%d%lld%d",&n,&p,&d);    head=1,tail=0;    ll now=0; ans=0,ni=1,re=0ll;    for(int i=1;i<=n;i++)    {        read(a[i]); now+=a[i]; re+=a[i];        if(i>d) now-=a[i-d];        while(head<=tail&&qs[tail]<=now) tail--;        q[++tail]=max(1,i-d+1); qs[tail]=now;        while(re-qs[head]>p)        {            re-=a[ni++];            while(ni>q[head]) head++;        }        ans=max(ans,i-ni+1);    }    printf("%d\n",ans);    return 0;}