给定长度为 的序列 ,我们定义一种将 划分为若干段的方案的价值为每一段的最大值减去最小值的差的乘积,你需要求出所有划分方案的价值的总和,答案对 取模。
首先显然可以设 表示前 个数的和,通过枚举最后一段来转移,但是这样做是 的。
考虑把最后一段的 和 单独考虑,求出 的贡献和 的贡献,再作差。可以用单调栈维护 和 改变的位置,然后用前缀和来转移。
部分代码:
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sm[0]=1;
int sm0=0,sm1=0;
for(int i=1;i<=n;i++)
{
while(mxq[0]>0&&a[mxq[mxq[0]]]<=a[i]) sm1=(sm1-1ll*a[mxq[mxq[0]]]%p*(sm[mxq[mxq[0]]-1]-(mxq[0]>1?sm[mxq[mxq[0]-1]-1]:0)+p)%p+p)%p,mxq[0]--;
while(mnq[0]>0&&a[mnq[mnq[0]]]>=a[i]) sm0=(sm0-1ll*a[mnq[mnq[0]]]%p*(sm[mnq[mnq[0]]-1]-(mnq[0]>1?sm[mnq[mnq[0]-1]-1]:0)+p)%p+p)%p,mnq[0]--;
sm1=(sm1+1ll*a[i]%p*(sm[i-1]-(mxq[0]>0?sm[mxq[mxq[0]]-1]:0)+p)%p)%p;
sm0=(sm0+1ll*a[i]%p*(sm[i-1]-(mnq[0]>0?sm[mnq[mnq[0]]-1]:0)+p)%p)%p;
mxq[++mxq[0]]=i;
mnq[++mnq[0]]=i;
int dpi=(sm1-sm0+p)%p;
sm[i]=(sm[i-1]+dpi)%p;
if(i==n) printf("%d\n",dpi%p);
}
return 0;
}