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

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.

 

posted @ 2017-03-23 23:58  Klaier  阅读(174)  评论(0编辑  收藏  举报