CF1691D Max GEQ Sum

<h2>思路</h2>
  1. 考虑 $a_i$ 作为最大值的区间 $[l,r]$。
  2. 在 $[l,r]$ 中如果存在一段包含 $a_i$ 的连续和大于 $a_i$,则判断为 $\texttt{NO}$;如果对于所有 $a_i$ 都不存在这样的连续和,则为 $\texttt{YES}$。

实现

  1. 单调栈。
  2. 求最大连续和,由于必须包含 $a_i$,则在 $[i,r]$ 中寻找最大数,在 $[l-1,i-1]$ 中寻找最小数,两者之差就是最大和。

最大数、最小数的查找使用 st 表。

注:由于查询区间包含位置 $0$,st 表的建立需要从 $0$ 开始。

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=2e5+5;
const ll INF=0x7ffffffffffffff;
int t,n,l[MAXN],r[MAXN];
ll a[MAXN],sum[MAXN]/前缀和/,st1[MAXN][20]/区间最大值/,st2[MAXN][20]/区间最小值/;
stack<int>s/单调栈/;
ll get_max(int l,int r)
{
int k=log2(r-l+1);
return max(st1[l][k],st1[r-(1<<k)+1][k]);
}
ll get_min(int l,int r)
{
int k=log2(r-l+1);
return min(st2[l][k],st2[r-(1<<k)+1][k]);
}
int main()
{
cin>>t;
while(t--)
{
bool flag=true;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
st1[i][0]=st2[i][0]=sum[i];
}
for(int j=1;(1<<j)<=n;j++)//st 表初始化
{
for(int i=0;i+(1<<j)-1<=n;i++)
{
st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1))][j-1]);
st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1))][j-1]);
}
}
s.push(0);
a[0]=INF;
for(int i=1;i<=n;i++)
{
while(!s.empty()&&a[i]>=a[s.top()])s.pop();
l[i]=s.top()+1;
s.push(i);
}
s.push(n+1);
a[n+1]=INF;
for(int i=n;i>=1;i--)
{
while(!s.empty()&&a[i]>=a[s.top()])s.pop();
r[i]=s.top()-1;
s.push(i);
}
for(int i=1;i<=n;i++)
{
ll mx=get_max(i,r[i]);
ll mn=get_min(l[i]-1,i-1);
if(a[i]<mx-mn)
{
cout<<"NO\n";
flag=false;
break;
}
}
if(flag)cout<<"YES\n";
}
return 0;
}

posted @   H2ptimize  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示