1. 程式人生 > >終於在nowcoder爆發了的懶惰

終於在nowcoder爆發了的懶惰

題目

這類題目我實在忍不了了
Emma,隨便做個nowcode比賽題吧,我在oj上也沒找到

題意

\(\sum_{L=1}^{n}\sum_{R=i}^{n}a[k](L<=k<=R)\),使得和最大
就是求所有子串的最大值之和

思路

我們用一個tot維護 \(\sum_{1}^{i}\)的字首最大值
\(tot<=>\sum_{1}^{i}\)的字首最大值$
我們容易發現,陣列中的值都是單調遞增的
然後我們就維護這個陣列,使他每次轉移的時候更新個答案ans就ok了
\(ans<=>前i個數的答案\)
維護的時候用單調棧就ok了
一開始我理解為單調佇列,其實他是個單調棧
他只有一個指標,也就是棧頂在移動
你也可以想象成左邊不動的單調佇列


對蒟蒻的我來說用語言是很難理解的
舉個例子(這裡我們只求子串最大值)

1 3 2

佇列為空,1進棧 tot[1]=1,ans[1]=1

1彈棧,3進棧 tot[2]=2*3, ans[2]=ans[1]+tot[2]=7;

2進棧 tot[3]=tot[2]+2=8, ans[3]=ans[2]+tot[3]=15;

(這裡包含了長度為1的子串)

需要注意的地方

這裡5w*5w是炸longlong的
所以

tot+=a[i]*(q[t]-q[t-1]);

這句話後半句是已經炸longlong的,炸longlong無處不在,還是隨手開longlong的穩啊

程式碼

#include <iostream>
#include <cstdio>
#define ll long long
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<1)+(x<<3)+s-'0';
    return x*f;
}
ll n,a[maxn],q[maxn];
ll solve() {
    ll ans=0,tot=0,t=0;
    FOR(i,1,n) {
        while(t>=1 && a[i]>=a[q[t]]) tot-=a[q[t]]*(q[t]-q[t-1]),t--;
        q[++t]=i;
        tot+=a[i]*(q[t]-q[t-1]);
        ans+=tot;
    }
    return ans;
}
int main() {
    int T=read();
    FOR(kkk,1,T) {
        n=read();
        FOR(i,1,n) a[i]=read();
        ll ans1=solve();
        FOR(i,1,n) a[i]=-a[i];
        ll ans2=solve();
        cout<<ans1+ans2<<"\n";
    }
    return 0;
}