洛谷 P6932 - [ICPC2017 WF]Money for Nothing(决策单调性分治)

洛谷题面传送门

不会决策单调性分治了 /ll,重新做道题找找感觉。

题意可以转化为平面上 \(n\) 个黑点和 \(m\) 个白点,要选一个黑点和一个白点,满足黑点在白点左下方,最大化黑点和白点围成的矩形的面积。很明显可能被选择的黑点按 \(x\) 坐标排序后,\(y\) 坐标是单调递减的;可能被选择的白点也同理。于是问题转化为对每个黑点找一个最优白点。

一开始想着斜率优化,然后发现是二维的根本做不了……简直蠢到家了。

正解是:如果将在单调栈上的黑点和白点都按横坐标排序,那么白点对应的最优黑点满足决策单调性。证明挺容易,很明显如果出现交叉,那么交换两个匹配点后,两矩形的面积和增加,因此必然有一者不是最优决策点。

于是直接分治即可。

const int MAXN = 5e5;
const int INF = 0x3f3f3f3f;
int n, m, ca, cb; ll res = 0;
pii ap[MAXN + 5], bp[MAXN + 5], a[MAXN + 5], b[MAXN + 5];
void solve(int l, int r, int pl, int pr) {
	if (l > r || pl > pr) return; int mid = l + r >> 1, id = 0; ll mx = -1e18;
	for (int i = pl; i <= pr; i++) if (b[i].fi > a[mid].fi || b[i].se > a[mid].se)
		if (1ll * (a[mid].fi - b[i].fi) * (a[mid].se - b[i].se) > mx)
			mx = 1ll * (a[mid].fi - b[i].fi) * (a[mid].se - b[i].se), id = i;
	chkmax(res, mx);
	if (id) solve(l, mid - 1, pl, id), solve(mid + 1, r, id, pr);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%d%d", &ap[i].fi, &ap[i].se);
	for (int i = 1; i <= m; i++) scanf("%d%d", &bp[i].fi, &bp[i].se);
	sort(ap + 1, ap + n + 1); sort(bp + 1, bp + m + 1, greater<pii>());
	int cur = INF; for (int i = 1; i <= n; i++) if (ap[i].se < cur) a[++ca] = ap[i], cur = ap[i].se;
	cur = -1; for (int i = 1; i <= m; i++) if (bp[i].se > cur) b[++cb] = bp[i], cur = bp[i].se;
	reverse(b + 1, b + cb + 1);
//	printf("a:\n"); for (int i = 1; i <= ca; i++) printf("%d %d\n", a[i].fi, a[i].se);
//	printf("b:\n"); for (int i = 1; i <= cb; i++) printf("%d %d\n", b[i].fi, b[i].se);
	solve(1, ca, 1, cb); printf("%lld\n", res);
	return 0;
}
posted @ 2022-07-13 19:43  tzc_wk  阅读(69)  评论(0)    收藏  举报