[Sdoi2016]征途
Description
Pine开始了从S地到T地的征途。
从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
帮助Pine求出最小方差是多少。
设方差是v,可以证明,v×m^2是一个整数。为了避免精度误差,输出结果时输出v×m^2。
Input
第一行两个数 n、m。
第二行 n 个数,表示 n 段路的长度
Output
一个数,最小方差乘以 m^2 后的值
Sample Input
5 2
1 2 5 8 6
1 2 5 8 6
Sample Output
36
HINT
1≤n≤3000,保证从 S 到 T 的总路程不超过 30000
1 #include<iostream> 2 #include<string> 3 #define LL long long 4 using namespace std; 5 6 int n,m,L[3005]={0}; 7 LL f[3005]={0},g[3005]={0}; 8 9 LL pow(long long x){ 10 return x*x; 11 } 12 13 LL cal(int k,int j){ 14 return g[k]+pow(L[k])-2*L[j]*L[k]; 15 } 16 17 double slope(int j,int k,int i){ 18 double y2=g[k]+pow(L[k]); 19 double y1=g[j]+pow(L[j]); 20 double x2=2*L[k]; 21 double x1=2*L[j]; 22 23 double y3=g[i]+pow(L[i]); 24 double x3=2*L[i]; 25 26 return (y2-y1)/(x2-x1)>(y3-y2)/(x3-x2); 27 } 28 29 int main() 30 { 31 cin>>n>>m; 32 33 for(int i=1;i<=n;++i) 34 { 35 cin>>L[i]; 36 L[i]+=L[i-1]; 37 } 38 39 for(int i=1;i<=n;++i) 40 g[i]=pow(L[i]); 41 42 for(int i=2;i<=m;++i) 43 { 44 int Q[3005]={0},head=0,tail=0; 45 for(int j=1;j<=n;++j) 46 { 47 while(head<tail&&cal(Q[head],j)>cal(Q[head+1],j)) head++; 48 int k=Q[head]; 49 f[j]=g[k]+pow(L[j]-L[k]); 50 51 while(head<tail&&slope(Q[tail-1],Q[tail],j)) tail--; 52 Q[++tail]=j; 53 } 54 55 for(int j=1;j<=n;++j) g[j]=f[j]; 56 } 57 58 cout<<m*g[n]-pow(L[n])<<endl; 59 60 61 // system("pause"); 62 63 }