首页 > 其他分享 >CF1691D

CF1691D

时间:2023-02-05 17:23:15浏览次数:57  
标签:ch const CF1691D int sum 区间 define

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; }

 

标签:ch,const,CF1691D,int,sum,区间,define
From: https://www.cnblogs.com/Willette/p/17093619.html

相关文章