题意
有一个长度为 (n) 的序列 (a_i) ((n le 4 imes 10^7)), 求
的最小值.
思路
结论: 上述式子能取到最小值, 当且仅当最后一块 (即(sum_{i=k_{j-1}+1}^{n} a_i)) 取到了最小值.
证明: 暂时不会.
那我们就 (dp) 保证最后一块最小就行了.
设 (val[i]) 为以 (i) 结尾的序列的最后一块的最小值.
那么对于每一位 (i) 只需从 (i-1) 到 (0) 找到第一位 (j) 满足 (sum[i] - sum[j] ge val[j]), (val[i]) 即为 (sum[i]-sum[j]). ((sum) 为前缀和数组)
可以发现, 每次 (j) 值是有单调性的, 所以可以考虑单调队列优化.
队头的筛选很简单, 满足要求就 +1, 找到最后一个满足条件的 (j) 即可.
再考虑队尾的处理, 如果只是单纯的把当前的 (i) 加入队列中的话, 就会出现 "队列中后面满足但前面不满足的情况",
比如说下面这个例子.
7 0
15 19 14 1 5 7 17
设 (lst[i]) 为 (i) 的上一个块的终点.
在上面这个例子中, (lst[6]=2), 那么 (i==7) 时, 队头 (t1) 就会在 (2) 的位置,
但是, 由于 (lst[3]=1, val[3]=33), 而 (sum[7]-sum[3]==30 < val[3]), 所以 (t1) 会停在 (3).
但是, (lst[5]=2), 所以 (lst[7]) 实际上是可以取到 (5) 的.
所以, 我们可以发现, 要在加入一个新的选项时, 要去除一些不优情况.
首先想到的是把队列中 (val[que[t2]] > val[i]) 的去掉, ( (t2) 为队尾 )
但是这样可能会导致后面的一些 (i) 取不到满足要求的 (j),
所以我们还要保证当 (que[t2]) 对于后面的某个数满足要求时, (i) 也一定满足要求.
设 (t) 为后面的一个点, 那么就要满足: (sum[t]-sum[que[t2]] ge val[que[t2]]) 可以推导到 (sum[t]-sum[i] ge val[i]).
即 $ val[que[t2]] + sum[que[t2]] ge val[i] + sum[i] $,
那么, 在把 (i) 加入队尾的时候判断上述条件, 若满足则 (t2--).
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e5+7;
int n,ty,que[N],t1=1,t2,pre[N];
ll a[N],sum[N],val[N],ans;
int main(){
cin>>n>>ty;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
que[++t2]=0;
for(int i=1;i<=n;i++){
while(t1<t2&&sum[i]-sum[que[t1+1]]>=val[que[t1+1]]) t1++;
pre[i]=que[t1];
val[i]=sum[i]-sum[que[t1]];
while(t2>=t1&&val[i]+sum[i]<=val[que[t2]]+sum[que[t2]]) t2--;
que[++t2]=i;
}
int p=n;
while(p){
ans+=val[p]*val[p];
p=pre[p];
}
printf("%lld
",ans);
return 0;
}