JZOJ 5190. 景中人 (找性质+dp+记忆化实现)

https://gmoj.net/senior/#contest/show/2391/1

(Tle 10, n le 100)

发现不会有两个矩形的横坐标是相交的,这样不如变成不相交更优。

但是会有两个矩形是包含的。

(f[i][j][k])表示覆盖横坐标(in [i,j]),纵坐标(>k),的点最少要几个矩形。

转移一是枚举分界点(u),分成左边和右边。

转移二是就拿一个尽量高的横坐标[i,j]的矩形去覆盖。

坐标要离散,实现可以记忆化。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("
")
using namespace std;

const int N = 105;

int T, n, S;

struct P {
	int x, y;
} a[N];

int c[N], c0, d[N], d0;

int bz[N][N][N];
int f[N][N][N];

int dg(int x, int y, int z) {
	if(x > y || z >= d0) return 0;
	if(bz[x][y][z]) return f[x][y][z];
	bz[x][y][z] = 1;
		
	int mi = 1e9;
	fo(i, 1, n) if(x <= a[i].x && a[i].x <= y && a[i].y > z)
		mi = min(mi, a[i].y);
	if(mi == 1e9) return f[x][y][z] = 0;
	
	int ans = 1e9;
	fo(j, x, y - 1) ans = min(ans, dg(x, j, z) + dg(j + 1, y, z));
	
	ll h = max(1, c[y] - c[x]);
	int t = d0;
	if(h <= S) {
		fo(i, mi, d0) if(h * d[i] > S) {
			t = i - 1; break;
		}
		if(t > z)
			ans = min(ans, dg(x, y, t) + 1);
	}
	return f[x][y][z] = ans;
}

int main() {
	freopen("scene.in", "r", stdin);
	freopen("scene.out", "w", stdout);
	scanf("%d", &T);
	fo(ii, 1, T) {
		scanf("%d %d", &n, &S);
		c0 = d0 = 0;
		fo(i, 1, n) {
			scanf("%d %d", &a[i].x, &a[i].y);
			c[++ c0] = a[i].x;
			d[++ d0] = a[i].y;
		}
		sort(c + 1, c + c0 + 1);
		c0 = unique(c + 1, c + c0 + 1) - (c + 1);
		sort(d + 1, d + d0 + 1);
		d0 = unique(d + 1, d + d0 + 1) - (d + 1);
		fo(i, 1, n) {
			a[i].x = lower_bound(c + 1, c + c0 + 1, a[i].x) - c;
			a[i].y = lower_bound(d + 1, d + d0 + 1, a[i].y) - d;
		}
		
		fo(i, 1, c0) fo(j, i, c0) fo(k, 0, d0) bz[i][j][k] = 0;
		pp("%d
", dg(1, c0, 0));
	}
}
原文地址:https://www.cnblogs.com/coldchair/p/12851152.html