题目链接:https://codeforces.com/problemset/problem/1408/D
要让所有的罪犯逃离,必须满足对于每一对罪犯和探照灯 ((i,j)) : 要么 (a[i] > c[j]), 要么 (b[i] > d[j])
所以对于 ((i,j)), 处理出罪犯 (i) 逃离信号灯 (j),所需要向上移动 (x) 步,或向右移动 (y) 步的对 ((x,y)).(如果罪犯 (i) 本来就不会被探照灯 (j) 照到,则跳过)
所有罪犯都成功逃离,即所有 ((x,y)) 对都被满足
处理好后,将所有 ((x,y)) 对按横坐标 (x) 排序,然后枚举所有罪犯向上移动的距离 (i), 对于所有 (x <= i) 的对,已经被满足了,而所有 (x > i) 的对,则只能通过向右移动来满足,也即找出剩余对中最大的 (y), 这个可以用后缀最大值来优化到 (O(1))
所以复杂度即为 (O(nm + 1e6))
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 2010;
int n, m, tot = 0;
int a[maxn], b[maxn], c[maxn], d[maxn], mx[maxn * maxn];
struct Node{
int x, y;
bool operator < (const Node &t) const{
return x < t.x;
}
}node[maxn * maxn];
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read(), m = read();
for(int i = 1 ; i <= n ; ++i) a[i] = read(), b[i] = read();
for(int i = 1 ; i <= m ; ++i) c[i] = read(), d[i] = read();
// n * m 个条件都要满足
for(int i = 1 ; i <= n ; ++i){
for(int j = 1 ; j <= m ; ++j){
if(a[i] <= c[j] && b[i] <= d[j]) {
node[++tot].x = c[j] - a[i] + 1;
node[tot].y = d[j] - b[i] + 1;
}
}
}
sort(node + 1, node + 1 + tot);
for(int i = tot ; i >= 0 ; --i){
mx[i] = max(mx[i + 1], node[i].y);
}
// printf("node:
");
// for(int i = 1 ; i <= tot ; ++i) printf("%d %d
", node[i].x, node[i].y); printf("
");
// for(int i = 1 ; i <= tot ; ++i) printf("%d ", mx[i]); printf("
");
int ans = 1000000007;
int j = 0;
for(int i = 0 ; i <= 1000001 ; ++i){
while(node[j + 1].x <= i && j < tot) ++j;
// printf("%d %d
", i, j);
ans = min(ans, i + mx[j + 1]);
}
printf("%d
", ans);
return 0;
}