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;
}
posted @ 2020-12-05 20:16  Tartarus_li  阅读(91)  评论(0编辑  收藏  举报