Google Kickstart2022 Round G Problem C 快乐子数组

有点思路,但还需要细想

思路

一眼上去,应该是写单调队列,但是不是像写滑动窗口一样写
设前缀和为pre,如果一个区间\([l,r]\)满足条件,那么\(pre[l-1]<min(pre[l],pre[l+1],.....,pre[r]\)
根据这一点,
我们每次枚举到i,只需要统计左端有多少个相对应的j使得pre[j]<pre[i]即可,这时就可以用单调队列,维护一个单调递增的pre队列,使得队列中的值始终小于pre[i],这时队列中的任意一个pre都可以与pre[i]满足题意
再结合代码应该能懂了

另外还有单调栈的做法:传送门

CODE

#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int n;
int t;
const int maxn=4e5+10;
int q[maxn<<1];
ll pre[maxn];
ll ans=0;
void solve(){
    cin>>n;
    
    int l=1,r=0;q[++r]=0;
    ll sum=0;
    for(int i=1;i<=n;++i){
        cin>>pre[i];
        pre[i]+=pre[i-1];
    }
    for(int i=1;i<=n;++i){
        while(l<=r && pre[q[r]]>pre[i]){
            sum-=pre[q[r]];
            --r;
        }
        if(r-l+1>0) ans+=(ll)pre[i]*(r-l+1)-sum;
        sum+=pre[i];
        q[++r]=i;
    }
    
    return ;
}
int main(){
    cin.tie(0);cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>t;
    for(int i=1;i<=t;++i){
        ans=0;
        solve();
        cout<<"Case #"<<i<<": "<<ans<<endl;
    }
    return 0;
}

单调栈

#include<bits/stdc++.h>

using namespace std;
#define int long long 
int n;
const int maxn=4e5+10;
int top=0;
int pre[maxn];
int sum[maxn];
int st[maxn];
int t;
int cnt=0;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;++i){
            int x;
            cin>>x;
            pre[i]=pre[i-1]+x;
            sum[i]=sum[i-1]+x*(n-i);
        }
        long long ans=0;
        top=0;
        pre[n+1]=-1e9;
        st[++top]=n+1;
        for(int i=n;i>=0;--i){
            while(pre[st[top]]>=pre[i])--top;
            int j=st[top];
            st[++top]=i;
            ans+=sum[j-1]-sum[i]-(pre[j-1]-pre[i])*(n-j);
        }
        cout<<"Case #"<<++cnt<<": "<<ans<<endl;
        
    }
}

两种方法对比

其实题目要求找所有满足sum[j]<sum[i]且j<i的区间和(sum为前缀和)
单调队列从前往后,固定了i,然后在队列中找满足条件的j
单调栈从后往前,固定了j,在栈中找满足条件的i

反思

虽然上去一眼想到了做法,单调队列,因为与模板有点像,但是具体实施时又发现貌似不好处理符合区间的值

从这个题中我们可以学到的是,单调队列的维护对象可以是多种多样的,不一定和模板是相同的

posted @ 2024-12-13 11:11  归游  阅读(5)  评论(2编辑  收藏  举报