Codeforces Round #577D. Treasure Hunting(二分+DP)

Treasure Hunting

You are on the island which can be represented as a n×mn×m table. The rows are numbered from 1 to n and the columns are numbered from 1 to m. There are kk treasures on the island, the ii-th of them is located at the position (ri,ci).

Initially you stand at the lower left corner of the island, at the position (1,1). If at any moment you are at the cell with a treasure, you can pick it up without any extra time. In one move you can move up (from (r,c) to(r+1,c)), left (from (r,c) to (r,c−1)), or right (from position(r,c) to(r,c+1)). Because of the traps, you can't move down.

However, moving up is also risky. You can move up only if you are in a safe column. There are qq safe columns: b1,b2,…,bq. You want to collect all the treasures as fast as possible. Count the minimum number of moves required to collect all the treasures.

Input

The first line contains integers n, mm, k and q (2≤n,m,k,q≤2⋅105, q≤m) — the number of rows, the number of columns, the number of treasures in the island and the number of safe columns.

Each of the next kk lines contains two integers ri,ci(1≤ri≤n, 1≤ci≤m) — the coordinates of the cell with a treasure. All treasures are located in distinct cells.

The last line contains qq distinct integers b1,b2,…,bq(1≤bi≤m) — the indices of safe columns.

Output

Print the minimum number of moves required to collect all the treasures.

Examples

input

3 3 3 2
1 1
2 1
3 1
2 3

output

6

input

3 5 3 2
1 2
2 3
3 1
1 5

output

Copy

8

input

3 6 3 2
1 6
2 2
3 4
1 6

output

15

Note

In the first example you should use the second column to go up, collecting in each row treasures from the first column.

In the second example, it is optimal to use the first column to go up.

In the third example, it is optimal to collect the treasure at cell (1;6), go up to row 2 at column 6, then collect the treasure at cell (2;2), go up to the top row at column 1 and collect the last treasure at cell (3;4). That's a total of 15 moves.

链接:https://codeforces.com/problemset/problem/1201/D

题意:k个点宝藏,q个安全列,最少步数收集所有宝藏。

每个位置可以往左、右走,只有在安全列位置时,才可以往上走,不可以向下走。

题解:只考虑每一行宝藏的最左边a[i][0]、最右边a[i][1],

因为将每一行宝藏收集完最短路径的终点只会发生在最左边、最右边。

最左边行结束dp[i][0],最右边结束dp[i][1],

并且i+1行继承第i行的计算时,

选择a[i][0](l)左右两边最近安全列q、w 和 a[i][1](r)左右两边最近安全列q、w,向上转移

寻找l或者r时的最近距离的q、w用二分查找,

状态转移方程每次选择最小值。

(画一下图就明白了~)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
int n,m,len;
long long a[200005][2];
long long b[200005];
long long er_b[200005][2];
long long dp[200005][2];
void solve()
{
	memset(dp,INF,sizeof(dp));
	for(int i=1;i<=m;i++)
	{
		er_b[i][0]=er_b[i][1]=INF;
		int top=lower_bound(b+1,b+len+1,i)-b;
		if(i==b[top])
		er_b[i][0]=er_b[i][1]=i;
		else if(top>1&&top<=len)
		{
			er_b[i][0]=b[top-1];
			er_b[i][1]=b[top];
		}
		else if(top==1)
		{
			er_b[i][1]=b[top];
		}
		else if(top==len+1)
		{
			er_b[i][0]=b[len];
		}
	}
	long long  l,r,top;
	if(a[1][0]!=INF)
	{
		dp[1][0]=abs(1-a[1][1])+abs(a[1][1]-a[1][0]);
		dp[1][1]=abs(1-a[1][1]);
		l=a[1][0];
		r=a[1][1];
		top=1;
	}
	else
	{
		dp[1][0]=0;
		dp[1][1]=0;
		top=1;
		l=r=1;
	}
	for(int i=2;i<=n;i++)
	{
		if(a[i][0]!=INF)
		{
			dp[i][0]=min(dp[i][0],(long long)(abs(er_b[l][0]-a[i][1])+abs(a[i][1]-a[i][0])+abs(er_b[l][0]-l)+dp[top][0]+(i-top)));	/*左->左*/
			dp[i][0]=min(dp[i][0],(long long)(abs(er_b[l][1]-a[i][1])+abs(a[i][1]-a[i][0])+abs(er_b[l][1]-l)+dp[top][0]+(i-top)));
			dp[i][0]=min(dp[i][0],(long long)(abs(er_b[r][0]-a[i][1])+abs(a[i][1]-a[i][0])+abs(er_b[r][0]-r)+dp[top][1]+(i-top)));	/*右->左*/
			dp[i][0]=min(dp[i][0],(long long)(abs(er_b[r][1]-a[i][1])+abs(a[i][1]-a[i][0])+abs(er_b[r][1]-r)+dp[top][1]+(i-top)));
							
			dp[i][1]=min(dp[i][1],(long long)(abs(er_b[l][0]-a[i][0])+abs(a[i][1]-a[i][0])+abs(er_b[l][0]-l)+dp[top][0]+(i-top)));
			dp[i][1]=min(dp[i][1],(long long)(abs(er_b[l][1]-a[i][0])+abs(a[i][1]-a[i][0])+abs(er_b[l][1]-l)+dp[top][0]+(i-top)));
			dp[i][1]=min(dp[i][1],(long long)(abs(er_b[r][0]-a[i][0])+abs(a[i][1]-a[i][0])+abs(er_b[r][0]-r)+dp[top][1]+(i-top)));
			dp[i][1]=min(dp[i][1],(long long)(abs(er_b[r][1]-a[i][0])+abs(a[i][1]-a[i][0])+abs(er_b[r][1]-r)+dp[top][1]+(i-top)));
			l=a[i][0];
			r=a[i][1];
			top=i;
		}
	}
	dp[n][0]=dp[top][0];
	dp[n][1]=dp[top][1];
	cout<<min(dp[n][0],dp[n][1])<<endl;
}
int main()
{
	int q;
	long long x,y;
	scanf("%d%d%d%d",&n,&m,&q,&len);
	for(int i=1;i<=200002;i++)
	a[i][0]=INF;
	for(int i=1;i<=q;i++)
	{
		scanf("%I64d%I64d",&x,&y);
		a[x][0]=min(a[x][0],y);
		a[x][1]=max(a[x][1],y);
	}
	for(int i=1;i<=len;i++)
	scanf("%I64d",&b[i]);
	sort(b+1,b+len+1);
	solve();
	return 0;
}
发布了39 篇原创文章 · 获赞 27 · 访问量 4122

猜你喜欢

转载自blog.csdn.net/qq_43381887/article/details/102508344
今日推荐