zoukankan      html  css  js  c++  java
  • [POI2015]WIL-Wilcze doły(单调队列)

    题意

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

    (1<=d<=n<=2000000,0<=p<=10^16)

    题解

    一看以为是DP结果想了半天想不出来。(其实有点像)

    然后又以为是单调队列套单调队列。。。(我也不知到这是什么)

    但跟答案很像了,就差一点。

    假如给定选择区间,一定要去掉和最大的连续d个数。

    所以我们枚举以右端点r,用单调对列维护当前区间内最大的连续d个数的值。

    在区间扩展时(r++)我们判断当前区间在去掉最大的连续d个数的值之后是否大于p

    若大于p则l++更新单调队列。对于每一个右端点都有一个最优解。取最大就好了。

    o(n)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 const long long N=2000100;
     8 long long n,p,d,a[N],sum1[N],sum[N],q[N],l,head,tail,tot,ans;
     9 int main(){
    10     scanf("%lld%lld%lld",&n,&p,&d);
    11     for(long long i=1;i<=n;i++){
    12         scanf("%lld",&a[i]);
    13         sum1[i]=sum1[i-1]+a[i]; 
    14     }
    15     for(long long i=1;i<=d;i++){
    16         sum[i]=sum1[i];
    17     }
    18     for(long long i=d+1;i<=n;i++){
    19         sum[i]=sum1[i]-sum1[i-d];
    20     }
    21 //    for(int i=1;i<=n;i++){
    22 //        cout<<sum[i]<<" ";
    23 //    }
    24 //    cout<<endl;
    25     head=1;
    26     tail=0;
    27     l=1;
    28     for(long long i=1;i<=n;i++){
    29         tot+=a[i];
    30         while(sum[i]>=sum[q[tail]]&&head<=tail)tail--;
    31         q[++tail]=i;
    32         while(tot-sum[q[head]]>p&&head<=tail){
    33             tot-=a[l];
    34             l++;
    35             while(q[head]-d<l&&head<=tail)head++;
    36         }
    37         ans=max(ans,i-l+1);
    38     }
    39     printf("%lld",ans);
    40     return 0;
    41 }
  • 相关阅读:
    BZOJ3813 奇数国
    BZOJ2735 世博会
    BZOJ2081 [Poi2010]Beads
    BZOJ3276 磁力
    BZOJ2054 疯狂的馒头
    BZOJ2610 [Poi2003]Monkeys
    BZOJ2428 [HAOI2006]均分数据
    BZOJ2120 数颜色
    BZOJ2527 [Poi2011]Meteors
    补比赛——牛客OI周赛9-普及组
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9445269.html
Copyright © 2011-2022 走看看