bzoj4518 [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
Source
鸣谢Menci上传
把方差的式子写成平方平均数减平均数的平方,发现只要最小化平方。
f[i,j]表示前i段分成j段的最小***
dp方程f[i,j]=min(f[k,j-1]+(s[i]-s[k])^2) k<i
在搞一搞斜率优化,几乎跟hdu3507一模一样。
1 program journey(input,output); 2 var 3 s:array[0..3030]of double; 4 f:array[0..3030,0..3030]of double; 5 q:array[0..3030]of longint; 6 n,m,i,j,h,t:longint; 7 function up(x,y:longint):double; 8 begin 9 exit(f[x,j-1]-f[y,j-1]+sqr(s[x])-sqr(s[y])); 10 end; 11 function down(x,y:longint):double; 12 begin 13 exit((s[x]-s[y])*2); 14 end; 15 begin 16 assign(input,'journey.in');assign(output,'journey.out');reset(input);rewrite(output); 17 readln(n,m);s[0]:=0; 18 for i:=1 to n do begin read(s[i]);s[i]:=s[i]+s[i-1];f[i,1]:=sqr(s[i]); end; 19 for j:=2 to m do 20 begin 21 h:=1;t:=1;q[1]:=j-1; 22 for i:=j to n do 23 begin 24 while (h<t) and (up(q[h+1],q[h])<=s[i]*down(q[h+1],q[h])) do inc(h); 25 f[i,j]:=f[q[h],j-1]+sqr(s[i]-s[q[h]]); 26 while (h<t) and (up(i,q[t])*down(q[t],q[t-1])<=up(q[t],q[t-1])*down(i,q[t])) do dec(t); 27 inc(t);q[t]:=i; 28 end; 29 end; 30 write(m*f[n,m]-sqr(s[n]):0:0); 31 close(input);close(output); 32 end.