JZOJ 5190. 景中人 (找性质+dp+记忆化实现)
https://gmoj.net/senior/#contest/show/2391/1
\(T\le 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("\n")
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\n", dg(1, c0, 0));
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址