nssl 1499.温暖题

D e s c r i p t i o n Description Description

给定 n n n个点的坐标 ( x i , y i ) (x_i,y_i) (xi,yi),规定 x i ≥ 0 , y i ≥ 0 x_i\geq 0,y_i\geq 0 xi0,yi0,坐标为 ( x , y ) (x,y) (x,y)的点位于 m a x { x , y } max\{x,y\} max{x,y}层,现在要从 ( 0 , 0 ) (0,0) (0,0)出发,依次走完所有层(先走小的层,再走大的层)的所有点,求最小路径长度

数据范围: n ≤ 2 × 1 0 5 n\leq 2\times 10^5 n2×105


S o l u t i o n Solution Solution

首先每一层的点一定是从左上走到右下或者从右下走到左上,所以我们以层数为第一关键字,左上到右下为第二关键字排序,然后 d p dp dp一下每层的转移即可

具体地,设 f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]表示走完了前 i i i层,最终处于最左上/右下端的最短路径, s u m i sum_i sumi表示遍历前 i i i,转移有

f [ i ] [ 0 ] = m i n { f [ i − 1 ] [ 0 ] + d i s t ( l i − 1 , r i ) , f [ i − 1 ] [ 1 ] + d i s t ( r i − 1 , r i ) } + s u m i f[i][0]=min\{f[i-1][0]+dist(l_{i-1},r_i),f[i-1][1]+dist(r_{i-1},r_i)\}+sum_i f[i][0]=min{f[i1][0]+dist(li1,ri),f[i1][1]+dist(ri1,ri)}+sumi
f [ i ] [ 1 ] = m i n { f [ i − 1 ] [ 0 ] + d i s t ( l i − 1 , l i ) , f [ i − 1 ] [ 1 ] + d i s t ( r i − 1 , l i ) } + s u m i f[i][1]=min\{f[i-1][0]+dist(l_{i-1},l_i),f[i-1][1]+dist(r_{i-1},l_i)\}+sum_i f[i][1]=min{f[i1][0]+dist(li1,li),f[i1][1]+dist(ri1,li)}+sumi

然后就做完了,时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)


C o d e Code Code

#include
#include
#include
#include
#include 
#define LL long long
using namespace std;int n,m;
struct node{LL x,y,c;}a[200010];
LL f[200010][2];
vector<node>q[200010];
inline LL dis(node x,node y){return abs(x.x-y.x)+abs(x.y-y.y);}
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline bool cmp(node x,node y)
{
	if(x.c==y.c)
	{
		if(x.x==y.x) return x.y>y.y;
		return x.x<y.x;
	}
	return x.c<y.c;
}
signed main()
{
	n=read();
	for(register int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].c=max(a[i].x,a[i].y);
	sort(a+1,a+1+n,cmp);
	for(register int i=1,j;i<=n;i=j+1)
	{
	    j=i;
		while(a[j+1].c==a[i].c) j++;
		m++;
		for(register int k=i;k<=j;k++) q[m].push_back(a[k]);
	}
	memset(f,0x3f,sizeof(f));
	f[0][0]=f[0][1]=0;
	q[0].push_back((node){0,0,0});
	for(register int i=1;i<=m;i++)
	{
		node L=q[i][0],R=q[i][q[i].size()-1];
		LL sum=0;
		for(register int j=1;j<q[i].size();j++) sum+=dis(q[i][j],q[i][j-1]);
		node lastL=q[i-1][0],lastR=q[i-1][q[i-1].size()-1];
		f[i][0]=min(f[i-1][0]+dis(lastL,R),f[i-1][1]+dis(lastR,R))+sum;
		f[i][1]=min(f[i-1][0]+dis(lastL,L),f[i-1][1]+dis(lastR,L))+sum;
	}
	printf("%lld",min(f[m][0],f[m][1]));
}

你可能感兴趣的:(dp,nssl,1499,温暖题)