zoukankan      html  css  js  c++  java
  • [POI2010]Blocks

    题目大意:
      给你一个长度为n的数列,给你m个数k。
      对于每个k,你可以进行若干次操作,每次把一个超过k的数的多余部分移到旁边一个数。
      问对于每个k,进行若干次操作以后,最长的满足每个数都不小于k的区间长度。

    思路:
      一个区间可以通过若干次操作使得每个数都不小于k,当且仅当这个区间平均数大于等于k。
      对于每个k,我们可以先O(n)求出这个序列每个数减去k的前缀和。
      对于i>j,如果sum[i]>=sum[j],那么对于i之后的数,用i转移肯定比j更优。
      因此我们可以维护一个关于前缀和的单调递减栈。
      然后枚举区间的右端点,在单调栈中找到最左的满足前缀和之差大于等于0的左端点即可。

     1 #include<stack>
     2 #include<cstdio>
     3 #include<cctype>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const int N=1000001;
    13 int a[N];
    14 int64 sum[N];
    15 std::stack<int> s;
    16 int main() {
    17     const int n=getint(),m=getint();
    18     for(register int i=1;i<=n;i++) {
    19         a[i]=getint();
    20     }
    21     for(register int i=1;i<=m;i++) {
    22         const int k=getint();
    23         s.push(0);
    24         for(register int i=1;i<=n;i++) {
    25             sum[i]=sum[i-1]+a[i]-k;
    26             if(sum[i]<sum[s.top()]) s.push(i);
    27         }
    28         int ans=0;
    29         for(register int i=n;i;i--) {
    30             int j=i;
    31             while(!s.empty()&&sum[i]>=sum[s.top()]) {
    32                 j=s.top();
    33                 s.pop();
    34             }
    35             ans=std::max(ans,i-j);
    36         }
    37         printf("%d%c",ans," 
    "[i==m]);
    38         while(!s.empty()) s.pop();
    39     }
    40     return 0;
    41 }
  • 相关阅读:
    JavaScript闭包
    模块模式——方法
    产品与技术
    读书笔记
    屌丝求职记
    正则表达式regex狂记
    css狂记
    html狂记
    Android狂记忆
    关于调式
  • 原文地址:https://www.cnblogs.com/skylee03/p/8183776.html
Copyright © 2011-2022 走看看