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 种方法摆脱所有探照灯的监视:
- 一直向上走,直到纵坐标比所有探照灯的纵坐标都大
- 一直向右走,直到横坐标比所有探照灯的横坐标都大
- 向上走一段路后,再向右走一会儿,如下图中的点
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,m≤2000,所以我们可以用一个 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;
}