【BZOJ3156】防御准备 斜率优化DP
裸题,注意:基本的判断(求Min还是Max),因为是顺着做的,且最后一个a[i]一定要取到,所以是f[n]。
DP:f[i]=min(f[j]+(i-j-1)*(i-j)/2+a[i])
依旧设x>y且f[x]优于f[y](原来是通用方法。。。)
2*(f[x]-f[y]) +x^2+x-y^2-y=2*i*(x-y) ok了。
1 #include <iostream> 2 #include <cstdio> 3 #define N 1000000+100 4 #define ll long long 5 using namespace std; 6 ll f[N]; 7 int a[N],q[N]; 8 int n,i,l,r; 9 inline int read() 10 { 11 int ans=0,f=1; 12 char c; 13 while (!isdigit(c=getchar())) if (c=='-') f=-1; 14 ans=c-'0'; 15 while (isdigit(c=getchar())) ans=ans*10+c-'0'; 16 return ans*f; 17 } 18 inline ll Pow(ll x) {return x*x;} 19 inline double Get(int x,int y) {return (double)(2*(f[x]-f[y])+Pow(x)-Pow(y)+x-y)/(double)(x-y);} 20 int main() 21 { 22 n=read(); 23 for (int i=1;i<=n;i++) a[i]=read(); 24 for (int i=1;i<=n;i++) 25 { 26 while (l<r && Get(q[l+1],q[l])<2*i) l++; 27 f[i]=f[q[l]]+(i-q[l]-1)*(i-q[l])/2+a[i]; 28 while (l<r && Get(i,q[r])<Get(q[r],q[r-1])) r--; 29 q[++r]=i; 30 } 31 printf("%lld",f[n]); 32 return 0; 33 }
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
Sample Output
18
HINT
1<=N<=10^6,1<=Ai<=10^9
Source
—Anime Otaku Save The World.