洛谷2629好消息,坏消息的解析——单调队列的应用

版权声明:转载请注明原出处啦(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82079652

题目:luogu2629.

题目大意:uim得到了n条消息,现在他要一次传递给老板,但是老板有一个心情值,初始为0,每个消息有一个值a[i],老板听到一个消息后的心情值为当前心情值+这个消息的值,若老板心情<0,uim就会被炒,所以现在uim要从第k个开始传递,现在他想知道有多少个k可以使得他不被炒.

这道题一开始还以为是求方案数,一下子想到了DP.

一看必须按顺序,所以这道题不是DP.

现在我们来看一看什么情况下uim不会被炒,我们假设A[i]表示a[i]的前缀和,那么当min_{k\leq i\leq n}(A[i]-A[k-1])\geq 0min_{1\leq i<k}(A[m]-A[k]+A[i])\geq 0的时候uim不会被炒.

我们发现其实这里面的东西除了A[i]以外都是常量,所以我们的只需要快速知道min(A[i])的值就可以了.

用什么来维护呢?线段树或者堆当然可以(不过大概率会超时),但是我们还有一种更简单的数据结构——单调队列.

我们直接用两个单调队列存储当前的最小值就可以了,或者说是前缀min.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
int n,sum;
LL a[N+9],u[N+9],d[N+9];
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%lld",&a[i]);
}
Abigail work(){
  for (int i=1;i<=n;i++)
    a[i]+=a[i-1];
  u[1]=a[1];d[n]=a[n];
  for (int i=2;i<=n;i++)
    u[i]=min(u[i-1],a[i]);
  for (int i=n-1;i>=1;i--)
    d[i]=min(d[i+1],a[i]);
  for (int i=1;i<=n;i++)
    if (d[i]-a[i-1]>=0&&a[n]-a[i-1]+u[i-1]>=0) sum++;
}
Abigail outo(){
  printf("%d\n",sum);
}
int main(){
  int T=1;
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/82079652