【ZJOI2017 Round1练习&BZOJ5350】D5T1 masodik(DP,斜率优化)

题意:你要从(0,0)点走到(n,m), 每次只能往 x 轴或者 y 轴正方向移动一个单位距离。
从(i,j)移动到(i,j+1)的代价为 ri,从(i,j)移动到(i+1,j)的代价为 cj。

求最小代价。

对于 20%的数据, n, m<=5000。
对于 100%的数据, n, m<=10^5,0<ri,ci<=10^8。

思路:杜教原题

建出rc的下凸壳,每次走斜率大的那个。
证明?

• P q
• | |
• a--|-----|---
• b--|-----|---
• ra(q-p)+cp(a-b)<=rb(q-p)+cq(a-b)
• (ra-rb)(q-p)<=(cq-cp)(a-b)
• (ra-rb)/(a-b)<=(cq-cp)/(q-p)<=.......(more columns and
rows.
斜率?
每次走过路径斜率递增--->下凸
如何证明在下凸壳上?

下凸壳显然 假设当前是第x1行第y1列,下一个行和列是x2和y2,那么考虑是先沿行走还是先沿列走

先沿行走:r[x1]*(y2-y1)+c[y2]*(x2-x1)

先沿列走:r[x2]*(y2-y1)+c[y1]*(x2-x1)

r[x1]*(y2-y1)+c[y2]*(x2-x1)<r[x2]*(y2-y1)+c[y1]*(x2-x1)

(r[x2]-r[x1])/(x2-x1)>(c[y2]-c[y1])/(y2-y1)

于是先沿斜率大的走

 1 var x,y:array[0..200000,1..2]of longint;
 2     q1,q2:array[0..200000]of longint;
 3     r,c:array[0..200000]of int64;
 4     n,m,i,j,l1,l2:longint;
 5     k1,k2:double;
 6     ans:int64;
 7 
 8 function slope(i,j,k:longint):double;
 9 begin
10  exit((y[i,k]-y[j,k])/(x[i,k]-x[j,k]));
11 end;
12 
13 function clac(x1,y1,x2,y2,k:longint):int64;
14 begin
15  if k=1 then exit(r[x1]*(y2-y1)+c[y2]*(x2-x1))
16         else exit(c[y1]*(x2-x1)+r[x2]*(y2-y1));
17 end;
18 
19 begin
20  assign(input,'masodik.in'); reset(input);
21  assign(output,'masodik.out'); rewrite(output);
22  readln(n,m);
23  for i:=0 to n do
24  begin
25   read(y[i,1]); x[i,1]:=i; r[i]:=y[i,1];
26  end;
27  for i:=0 to m do
28  begin
29   read(y[i,2]); x[i,2]:=i; c[i]:=y[i,2];
30  end;
31  for i:=0 to n do
32  begin
33   while (l1>1)and(slope(i,q1[l1],1)<=slope(q1[l1-1],q1[l1],1)) do dec(l1);
34   inc(l1); q1[l1]:=i;
35  end;
36  for i:=0 to m do
37  begin
38   while (l2>1)and(slope(i,q2[l2],2)<=slope(q2[l2-1],q2[l2],2)) do dec(l2);
39   inc(l2); q2[l2]:=i;
40  end;
41  i:=1; j:=1;
42  while (i<l1)and(j<l2) do
43  begin
44   k1:=slope(q1[i],q1[i+1],1);
45   k2:=slope(q2[j],q2[j+1],2);
46   if k1>k2 then
47   begin
48    ans:=ans+clac(q1[i],q2[j],q1[i],q2[j+1],1);
49    inc(j);
50   end
51   else
52   begin
53    ans:=ans+clac(q1[i],q2[j],q1[i+1],q2[j],2);
54    inc(i);
55   end;
56  end;
57  while i<l1 do
58  begin
59   ans:=ans+clac(q1[i],q2[l2],q1[i+1],q2[l2],1);
60   inc(i);
61  end;
62  while j<l2 do
63  begin
64   ans:=ans+clac(q1[l1],q2[j],q1[l1],q2[j+1],2);
65   inc(j);
66  end;
67  writeln(ans);
68 
69 
70  close(input);
71  close(output);
72 end.

 

posted on 2017-03-07 11:30  myx12345  阅读(180)  评论(0编辑  收藏  举报

导航