P1951 [GDFZOJ] 徒步旅行
题目意思是给你一个坐标轴 , 其中 \(C_{x,y}=\max\{x,y\}\) , 要我们走完一种 \(C\) 的区域才能走下一个 \(C\) 的区域 , 求从 \((0,0)\) 到 \((end,end)\) 经过一些点的最小路径, 值都为曼哈顿距离。点数为 \(3 \times 10^5\)。
考虑一个 \(C\) 式矩阵 :
1 2 3 4
2 2 3 4
3 3 3 4
4 4 4 4
那么我们可以知道的是 , 每一层至少有一个不会改变的贡献 , 就是最左下角和最左上角的距离。然后问题变为上一层到下一层过渡总和的最小值。
我们就可以直接 \(\texttt{DP}\) 解决问题。\(\texttt{DP}\) 每一个最左下角点和最右上角点到下一个这样的点的最小值 , 记住贡献和贡献目标要相反。
Const
total=300000+10;
var
tiny,huge:array[-1..total,1..2] of longint;
fuck:array[-1..total,1..2] of longint;
i,j,l,r,a,b,n,ans,maxn,recf:longint;
bz:boolean;
function Max(a,b:longint):longint; begin if a>b then exit(a); exit(b); end;
function Min(a,b:longint):longint; begin if a<b then exit(a); exit(b); end;
function Dis(a,b,x,y:longint):longint; begin exit(abs(a-x)+abs(b-y)); end;
procedure Swap(var a,b:longint);var t:longint; begin t:=a; a:=b; b:=t; end;
begin
read(n);
for i:=1 to n do begin tiny[i,2]:=maxlongint; huge[i,1]:=maxlongint; end;
for i:=1 to n+1 do
begin
if i<=n then read(l,r) else begin l:=0; r:=0; end;
recf:=Max(l,r); maxn:=Max(maxn,recf);
if (tiny[recf,2]>r) then begin tiny[recf,1]:=l; tiny[recf,2]:=r; end;
if (huge[recf,1]>l) then begin huge[recf,1]:=l; huge[recf,2]:=r; end;
end;
for i:=1 to maxn do
begin
if tiny[i,2]=maxlongint then tiny[i,2]:=0;
if huge[i,1]=maxlongint then huge[i,1]:=0;
end;
for i:=1 to maxn do for j:=1 to 2 do fuck[i,j]:=maxlongint;
fuck[0,1]:=0; fuck[0,2]:=0; ans:=maxlongint;
for i:=0 to maxn do
begin
a:=Dis(tiny[i,1],tiny[i,2],tiny[i-1,1],tiny[i-1,2]);
b:=Dis(tiny[i,1],tiny[i,2],huge[i-1,1],huge[i-1,2]);
l:=Dis(huge[i,1],huge[i,2],tiny[i-1,1],tiny[i-1,2]);
r:=Dis(huge[i,1],huge[i,2],huge[i-1,1],huge[i-1,2]);
recf:=Dis(tiny[i,1],tiny[i,2],huge[i,1],huge[i,2]);
fuck[i,1]:=Min(fuck[i-1,1]+l,fuck[i-1,2]+r)+recf;
fuck[i,2]:=Min(fuck[i-1,1]+a,fuck[i-1,2]+b)+recf;
end;
ans:=Min(fuck[i,1]+Dis(0,0,tiny[i,1],tiny[i,2]),fuck[i,2]+Dis(0,0,huge[i,1],huge[i,2]));
writeln(ans);
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿