DP优化 G - Divide a Sequence
G - Divide a Sequence
前几天打的ABC,到最后两道还是不会,摆烂....以为是数学题,没想到是DP优化的题目...还是对数学题的恐惧太深了...
朴素的DP也是比较好好设的,考虑怎么优化,既然宏观上看不出来,我们不妨将其每一项都拆开,运用微积分的思想,没劝退,只是吓唬一下你。就是这样:
可以发现,如果我们能解决前一半的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;
}