CF1691D
Max GEQ Sum - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思维+单调栈+数据结构好题
所有(i,j)都符合 max( a[ i ],a[ i+1 ],a[ i+2 ],⋯,a[ j ]) ≥ a[ i ] +a[ i+1 ]+a[ i+2 ]+⋯a[ j ] 称之为好的
观察式子:发现区间和很容易算,关于在于 max 的值
我们用一个经典又难想的套路:当 a[ i ]为若干个区间的最大值时,判断是否符合题意
那么a[ i ]又如何作为一个区间的最大值呢?我们找到左边第一个大于它的下标L,右边第一个大于它的下标R,这显然是单调栈的模板。
那么a[ i ]所管辖的区间便是[ L+1,R-1 ],这段区间内的任何一段包含下标 i 区间的最大值都是 a[ i ]
接下来考虑 a[ i ] ≥(区间和)是否成立,这显然是判断 a[ i ] ≥ max(区间和)
现在我们假设这段区间的左端点为 l∈[ L+1,i ] ,右端点 r∈[ i,R-1 ]
区间和便是 sum[ r ]-sum[ l-1 ] ( l-1∈[ L , i-1 ] )
要使 sum[ r ]-sum[ l-1 ] ( l-1∈[ L , i-1 ] ) 最大,就是让 sum[ r ]最大,sum[ l-1 ] 最小
所以我们要查找 max( sum[ i~R-1] ) 和min( sum[ L~i-1 ] ),这显然ST表即可维护
细节重点:L有可能为0,所以ST表的下标不是从1开始,而是从0开始
Code:
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second const int N=2e5+10; //const int M=; //const int inf=0x3f3f3f3f; //const ll INF=0x3ffffffffffff; int T,n,L[N],R[N]; ll a[N],sum[N],f[N][25][2]; // 0最小,1最大 inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void sum_work() //细节:i 要从0开始 { for(int i=0;i<=n;i++) f[i][0][0]=f[i][0][1]=sum[i]; int t=log(n)/log(2)+1; for(int j=1;j<t;j++) { for(int i=0;i<=n-(1<<j)+1;i++) { f[i][j][0]=min(f[i][j-1][0],f[i+(1<<(j-1))][j-1][0]); f[i][j][1]=max(f[i][j-1][1],f[i+(1<<(j-1))][j-1][1]); } } } ll ask(int l,int r,int op) { int t=log(r-l+1)/log(2); if(op) return max(f[l][t][op],f[r-(1<<t)+1][t][op]); else return min(f[l][t][op],f[r-(1<<t)+1][t][op]); } int main() { // freopen("","r",stdin); // freopen("","w",stdout); T=read(); while(T--) { n=read(); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i]; sum_work(); stack<ll> s; for(int i=1;i<=n;i++) { while(!s.empty()&&a[s.top()]<=a[i]) s.pop(); if(!s.empty()) L[i]=s.top(); else L[i]=0; s.push(i); } while(!s.empty()) s.pop(); for(int i=n;i;i--) { while(!s.empty()&&a[s.top()]<=a[i]) s.pop(); if(!s.empty()) R[i]=s.top(); else R[i]=n+1; s.push(i);
} bool ok=1; for(int i=1;i<=n;i++) { ll Lmin=ask(L[i],i-1,0),Rmax=ask(i,R[i]-1,1); // l∈[L[i]+1,i] R∈[i,R[i]-1] if(Rmax-Lmin>a[i]) ok=0; // printf("%d %lld %lld\n",R[i]-1,mx,mn); } if(ok) puts("YES"); else puts("NO"); } return 0; }