DP优化 G Divide a Sequence

G - Divide a Sequence

前几天打的ABC,到最后两道还是不会,摆烂....以为是数学题,没想到是DP优化的题目...还是对数学题的恐惧太深了...
image
朴素的DP也是比较好好设的,考虑怎么优化,既然宏观上看不出来,我们不妨将其每一项都拆开,运用微积分的思想,没劝退,只是吓唬一下你。就是这样:
image
可以发现,如果我们能解决前一半的max的问题,后一半减去min的一部分是类似的。
考虑前面怎么做,可以发现其实就是前面的每一部分的范围都扩大进了a[i],让a[i]和他们取max,让我们想想哪个数据结构是符合这个?单调栈,我们维护一个从栈顶到栈低依次递增的栈,每个栈中元素额外维护一个它的f[]的和。当一个元素要被从栈中弹出时,它所维护的f[]值累加到把它弹出的元素即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10,P=998244353;
int n,a[N],top1,st1[N],top2,st2[N];
ll f[N],b1[N],b2[N],ans1,ans2;   
int main()
{   
//    freopen("1.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    f[0]=1;
    ans1=a[1];ans2=a[1];
    st1[++top1]=1;st2[++top2]=1;
    b1[1]=f[0];b2[1]=f[0];
    for(int i=2;i<=n;++i)
    {
        while(top1&&a[i]>=a[st1[top1]]) 
        {
            b1[i]=(b1[i]+b1[st1[top1]])%P; 
            ans1=((ans1-b1[st1[top1]]*a[st1[top1]]%P)%P+P)%P;
            --top1;
        }
        st1[++top1]=i;
        b1[i]+=f[i-1];
        ans1=(ans1+b1[i]*a[i]%P)%P;
        while(top2&&a[i]<=a[st2[top2]])
        {
            b2[i]=(b2[i]+b2[st2[top2]])%P;
            ans2=((ans2-b2[st2[top2]]*a[st2[top2]]%P)%P+P)%P;
            --top2;
        }
        st2[++top2]=i;
        b2[i]+=f[i-1];
        ans2=(ans2+b2[i]*a[i]%P)%P;
        f[i]=((ans1-ans2)%P+P)%P;
    }
    printf("%lld",f[n]);
    return 0;
}
原文地址:https://www.cnblogs.com/gcfer/p/15785847.html