https://www.lydsy.com/JudgeOnline/problem.php?id=3437
题干:略。
暴力做法:O(n^2),强行无脑dp。
整解:s1为一维前缀和,s2为二维前缀和(存 b[i]*i)
f[i] = min( f[j] + i*(s1[i]-s1[j]) - (s2[i] - s2[j]));
若 j 优于 k
则有 ( (f[ j ]+s2[ j ]) - ( f[ k ]+s2[ k ] ) ) / ( s1[ j ] - s1[ k ] ) < i
然后想起来 △y / △x = k
发现这道题是一道斜率优化的dp题。(但是并不需要维护凸包)
代码:
#include<cstdio> #include<algorithm> using namespace std; #define ll long long #define N 1000050 int n; ll a[N],b[N],s1[N],s2[N],f[N]; ll x(int i) { return s1[i]; } ll y(int i) { return f[i]+s2[i]; } ll q[N],hd,tl; int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%I64d",&a[i]); for(int i=1;i<=n;i++) { scanf("%I64d",&b[i]); s1[i] = s1[i-1]+b[i]; s2[i] = s2[i-1]+i*b[i]; } for(ll i=1;i<=n;i++) { while(hd<tl&&y(q[hd+1])-y(q[hd])<=i*(x(q[hd+1])-x(q[hd])))hd++; f[i] = a[i]+f[q[hd]]+i*s1[i]-i*s1[q[hd]]-s2[i]+s2[q[hd]]; while(hd<tl&&((y(i)-y(q[tl]))*(x(q[tl])-x(q[tl-1]))<=(y(q[tl])-y(q[tl-1]))*(x(i)-x(q[tl]))))tl--; q[++tl] = i; } printf("%I64d ",f[n]); return 0; }