codeforces 1408D. Searchlights (暴力 + 前缀优化)
题目链接: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:\n");
// for(int i = 1 ; i <= tot ; ++i) printf("%d %d\n", node[i].x, node[i].y); printf("\n");
// for(int i = 1 ; i <= tot ; ++i) printf("%d ", mx[i]); printf("\n");
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\n", i, j);
ans = min(ans, i + mx[j + 1]);
}
printf("%d\n", ans);
return 0;
}