BZOJ4518 Sdoi2016 征途 【斜率优化DP】 *
BZOJ4518 Sdoi2016 征途
Description
Pine开始了从S地到T地的征途。
从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
帮助Pine求出最小方差是多少。
设方差是v,可以证明,v×m2是一个整数。为了避免精度误差,输出结果时输出v×m2。
Input
第一行两个数 n、m。
第二行 n 个数,表示 n 段路的长度
Output
一个数,最小方差乘以 m^2 后的值
Sample Input
5 2
1 2 5 8 6
Sample Output
36
HINT
1≤n≤3000,保证从 S 到 T 的总路程不超过 30000
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 #define N 3010 5 struct Node{LL x,y;}q[N]; 6 double calc(Node a,Node b){return (double)(a.y-b.y)/(double)(a.x-b.x);} 7 bool check(Node a,Node b,Node c){return calc(a,b)>calc(b,c);} 8 LL dp[N][N],s[N]; 9 int n,m; 10 int main(){ 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;i++)scanf("%d",&s[i]),s[i]+=s[i-1]; 13 for(int i=1;i<=n;i++)dp[i][1]=s[i]*s[i]; 14 for(int p=2;p<=m;p++){ 15 int l=1,r=0; 16 q[1]=(Node){0,0}; 17 for(int i=1;i<=n;i++){ 18 while(l<r&&calc(q[l],q[l+1])<=2*s[i])l++; 19 Node t=q[l]; 20 dp[i][p]=-2*s[i]*t.x+t.y+s[i]*s[i]; 21 Node newnode=(Node){s[i],dp[i][p-1]+s[i]*s[i]}; 22 while(l<r&&check(q[r-1],q[r],newnode))r--; 23 q[++r]=newnode; 24 } 25 } 26 printf("%lld",m*dp[n][m]-s[n]*s[n]); 27 return 0; 28 }