D. Searchlights(思维 + 枚举)

该问题是一个关于策略优化的问题,要求计算出最小的移动次数,使所有强盗的位置通过向右或向上移动,避开探照灯的视线,达到安全配置。通过预处理并利用数组cnt记录信息,从最大向右移动距离开始枚举,结合纵坐标移动的最大值,求得最小总移动次数。
摘要由CSDN通过智能技术生成

Problem - D - Codeforces

坐标(a1, b1), (a2, b2),, (an, bn)有n个强盗,坐标(c1, d1), (c2, d2), .., (Cm, dm)。在一次移动中,你可以将每个强盗向右移动(每个强盗的a增加1)或将每个强盗向上移动(每个强盗的b增加1)。注意,你要么增加全部a,要么增加全部b,你不能在一些点增加a,而在另一些点增加b。如果ai < c,探照灯j可以看到强盗i;bi < dj。如果没有探照灯可以看到盗贼,那么盗贼的配置是安全的(例如,如果没有一对i, j使得探照灯j可以看到盗贼i)。要达到安全配置,您需要执行的最小移动次数是多少?输入第一行输入包含两个整数n和m (1 n, m2000):强盗的数量和探照灯的数量。接下来的n行每一行包含两个整数ai,bi (0 < ai,bi < 106),强盗的坐标。接下来的m行每一行包含两个整数c,, d,(0≤ci, di < 10f),探照灯的坐标。输出打印一个整数:达到安全配置所需的最小移动数。

Examples

input

Copy

1 1
0 0
2 3

output

Copy

3

input

Copy

2 3
1 6
6 1
10 1
1 10
7 7

output

Copy

4

input

Copy

1 2
0 0
0 0
0 0

output

Copy

1

input

Copy

7 3
0 8
3 8
2 7
0 10
5 5
7 0
3 5
6 6
3 11
11 5

output

Copy

6

请注意在第一个测试中,你可以将每个强盗向右移动三次。之后在坐标(3,0)中会有一个强盗。强盗的配置是安全的,因为唯一的探照灯看不到强盗,因为它在坐标(2,3)和3 > 2。在第二个测试中,你可以将每个强盗向右移动两次,向上移动两次。之后,强盗将在坐标(3,8),(8,3)中。很容易看出劫匪的配置是安全的。可以证明,你不能达到一个安全的配置使用不超过3步。

题解:
假设我们枚举整体坐标往右移动了多少,有些海盗可能走出了监视范围,但是可能有些还在监视范围内,所以我们应该再把这些海盗往上提一个最大的(监视灯y - 海盗y)

正常写肯定不行,我们应该预处理一下

由于n与m都很小,那我们找到任意两个海盗x1和监视灯x2

如果x1 <= x2

			if(a[i] <= c[j])
			{
				cnt[c[j] - a[i]] = max(cnt[c[j] - a[i]],d[j] - b[i] + 1);
			}

 代表向右移x2 - x1的点,需要满足题意,至少还要往上移动y2 - y1 + 1

接下来我们应该从大到小枚举往右移动了多少距离,

具体来说应该是最大的x2 - 最小的x1 + 1

(最大向右需要移动距离 + 1,代表考虑只移动x标,最小的x1都大于x2,其余肯定满足)开始枚举

接下来到最大x2 - 最小x1,代表横坐标移动这么多,但是其实还是不满足,因为这样刚好移动到边界上

所以要看整体纵坐标至少移动多少,我们刚才记录的cnt数组就用到了

整体移动的纵坐标要取最大,因为向右移动坐标越小,后面横坐标需要移动多的,肯定不满足,需要靠移动纵坐标满足

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define int long long
int n,m;
int cnt[1000050];
int a[2005];
int b[2005];
int c[2004];
int d[2004];
void solve()
{
	cin >> n >> m;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i] >> b[i];
	}
	for(int i = 1;i <= m;i++)
	{
		cin >> c[i] >> d[i];
	}
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= m;j++)
		{
			if(a[i] <= c[j])
			{
				cnt[c[j] - a[i]] = max(cnt[c[j] - a[i]],d[j] - b[i] + 1);
			}
		}
	}
	int ans = 1e6 + 1;
	int y = 0;
	for(int i = ans;i >= 0;i--)
	{
		y = max(y,cnt[i]);
		ans = min(ans,i + y);
	}
	cout << ans;
}


signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值