zoukankan      html  css  js  c++  java
  • [bzoj2086][Poi2010]Blocks

    [bzoj2086][Poi2010]Blocks

    Description

      给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1。经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于k。

      总共给出M次询问,每次询问给出的k不同,你需要分别回答。

    Input

      第一行两个正整数N (N <= 1,000,000)和M (M <= 50)。

      第二行N个正整数,第i个正整数表示a[i] (a[i] <= 10^9)。

      第三行M个正整数,第i个正整数表示第i次询问的k (k <= 10^9)。

    Output

      共一行,输出M个正整数,第i个数表示第i次询问的答案。

    Sample Input

    5 6
    1 2 1 1 5
    1 2 3 4 5 6

    Sample Output

    5 5 2 1 1 0
    

    思路

       首先我们看一看题,发现在题目中只是问最长的一段子序列的长度,并且没有限制操作多少次,所以我们能发现一个性质,当且仅当这个序列的平均数大于等于k时,这个序列为合法序列。所以我们可以将每一个数都减去k,再找出最长的子序列和大于零。由于是寻找连续数字的和,我们就可以想到运用前缀和,这样求一段区间就可以实现$O(1)$查询。我们再看,由于是求最长,所以我们要找到距离尽可能远的两个前缀和,且后者减去前者大于等于零,我们想到$n^2$算法,但分析时间复杂度明显不对,所以······

      经过思考,我们可以发现一个性质,就是如果已经遍历到$i$,现在有$j lt k$&&$sum[j] lt sum[k]$,显然选取$j$作为做左端点明显比$k$作为左端点要更优,所以我们可以根据这个性质发现维护栈时只有当当前$sum[i] lt sum[sta[top]]$时才能压入栈内,所以我们发现这是一个单调递减的栈。由于我们是从$1~n$找出的单调栈,所以我们更新答案应该从$n   ~ 1$,我们发现如果当$sum[i]-sum[sta[top]] ge 0$时,应该将栈顶弹出,这样不会是答案变小,但是有人会问,如果下一个的$sum$比现在这个的$sum$小,并且比栈顶的$sum$小,那不就更新不出答案了吗?但是我们仔细画一画,如果真的是那样,以下一个为右端点远没有以现在这个为右端点更优。

    代码

    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    #define N 1000001
    int n,m,k,ans;
    int number[N];
    long long sum[N];
    int f[N],idx,queue[N];
    void push(int ord)
    {
        while(idx&&sum[queue[idx]]>sum[ord]) idx--;
        queue[++idx]=ord;
    }
    void play()
    {
        idx=ans=0;
        queue[++idx]=0;
        for(int i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+number[i]-k;
            if(sum[i]<sum[queue[idx]]) queue[++idx]=i;
        }
        for(int i=n;i;i--)
        {
            while(sum[i]-sum[queue[idx]]>=0&&idx) idx--;
            ans=max(ans,i-queue[idx+1]);
        }
        printf("%d ",ans);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&number[i]);
        for(int j=1;j<=m;j++) scanf("%d",&k),play();
    }
  • 相关阅读:
    Visual Studio 2010使用Visual Assist X的方法
    SQL Server 2000 评估版 升级到 SQL Server 2000 零售版
    双网卡多网络单主机同时访问
    开发即过程!立此纪念一个IT新名词的诞生
    delphi dxBarManager1 目录遍历 转为RzCheckTree2树
    5320 软件集合
    delphi tree 从一个表复制到另一个表
    DELPHI 排课系统课表
    长沙金思维 出现在GOOGLE的 金思维 相关搜索里啦!!
    如何在DBGrid的每一行前加一个单选框?
  • 原文地址:https://www.cnblogs.com/yangsongyi/p/9424902.html
Copyright © 2011-2022 走看看