2021.04.03 日常总结——一些好题的记录(四)

25 篇文章 0 订阅
4 篇文章 0 订阅

CF1408D   Searchlights \color{green}{\texttt{CF1408D Searchlights}} CF1408D Searchlights

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

在这里插入图片描述

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

(自己画的图有点丑陋,请原谅)

显然,对于两个探照灯 ( i , j ) (i,j) (i,j),如果 i i i j j j 的探照范围内,则 i i i 是没有用的,可以删去。

于是剩下的有用的探照灯会按照横坐标递增,纵坐标递减的方式存在与坐标轴中,如下图所示:

在这里插入图片描述

对于任意一个海盗 i i i,可以有以下 3 3 3 种方法摆脱所有探照灯的监视:

  1. 一直向上走,直到纵坐标比所有探照灯的纵坐标都大
  2. 一直向右走,直到横坐标比所有探照灯的横坐标都大
  3. 向上走一段路后,再向右走一会儿,如下图中的点 G \texttt{G} G 的移动方式:
    在这里插入图片描述

当然了,如果已经摆脱了探照灯的控制,那么接下来再动也无所谓了。

最复杂的是第 3 3 3 种方法,但是我们可以知道,最优秀的方案应该是走到和某个探照灯等高(即纵坐标相等)时,不停地向右走,直到横坐标大于该探照灯。而全局最优方案下至少有一个点满足这个方案(除非最优解是第 1 , 2 1,2 1,2 种方案)。

所以我们开一个数组 f x f_{x} fx 表示所有的海盗先统一向上走了 x x x 步后,最少需要向右走几步。最后的答案就是 max ⁡ { i + f i } \max \{ i+f_{i} \} max{i+fi}

考虑到 n , m ≤ 2000 n,m \leq 2000 n,m2000,所以我们可以用一个 O ( n m ) O(nm) O(nm) 的枚举来求出 f x f_{x} fx

最后记得是倒序更新答案。

[code] \color{blue}{\texttt{[code]}} [code]

const int N=2e3+100;
const int M=1e6+100;
int ans,n,m,f[M],limit;
int a[N],b[N],c[N],d[N];
inline void ckmax(int &a,int b){
	a=a<b?b:a;//让 a 取到 a,b 间较大值 
}
inline void ckmin(int &a,int b){
	a=a>b?b:a;//让 a 取到 a,b 间较小值 
}
int main(){
	freopen("t1.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i],&b[i]);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&c[i],&d[i]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if (d[j]<b[i]) continue;
			ckmax(limit,d[j]-b[i]);
			ckmax(f[d[j]-b[i]],c[j]-a[i]+1);
		}
	ans=limit+1;//只向右边走,走出边界 
	for(int i=limit,maxn=0;i>=0;i--){
		ckmax(maxn,f[i]);ckmin(ans,i+maxn);
	}
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值