首先考虑暴力做法,$max (q[j] - p[i]) times (e[j] - d[i])$ ,当然要保证这两项都非负。然后我们发现如果存在$i,j$且$p[i] < p[j], d[i] < d[j]$,那么不管怎么选择,$i$都要优于$j$,所以我们把所有不可能作为答案的工厂给踢掉。然后对商店也同样这样处理。
然后这两个序列就在两个维度都满足了单调性,那么如果 DP 的话,是否会存在决策单调性呢?下面来简单证一下:
首先假设对于一个固定的商店,存在两个工厂$j < k$而且$k$优于$j$
$$(q[i] - p[j])times (e[i] - d[j]) < (q[i] - p[k])times (e[i] - d[k])$$
$$q[i]e[i] - q[i]d[j] - p[j]e[i] + p[j]d[j] < q[i]e[i] - q[i]d[k] - p[k]e[i] + p[k]d[k]$$
$$-q[i]d[j] - p[j]e[i] + p[j]d[j] < -q[i]d[k] - p[k]e[i] + p[k]d[k]$$
$$e[i]times (p[k] - p[j])- q[i]times (d[j] - d[k]) < p[k]d[k] - p[j]d[j]$$
然后$e[i] downarrow$ $q[i] uparrow$ $p[k] > p[j],d[j] > d[k]$,决策单调性得证。
然后我们可以考虑设计分治算法来解决这个问题。
$solve(le, ri, dl, dr)$表示在$[le, ri]$内选择商店,在$[dl, dr]$内选择工厂的 DP, 我们考虑枚举$[dl, dr]$ 内的所有工厂,对$mid = frac{le + ri}{2}$取最优决策$dm$,接着递归$solve(le, mi - 1, dl, dm)$以及$solve(mi + 1, ri, dm, dr)$就好了,
时间复杂度$O(nlog n)$
#include <bits/stdc++.h> using namespace std; #define ll long long #define up(i,j,n) for (register int i = j; i <= n; ++i) #define down(i,j,n) for (register int i = j; i >= n; --i) #define cmax(a,b) a = max (a, b) #define cmin(a,b) a = min (a, b) #define pii pair<int, int> #define fi first #define se second const int MAXN = 5e5 + 5; const int oo = 0x3f3f3f3f; inline int read(){ char ch = getchar(); int x = 0, f = 1; while (ch > '9' || ch < '0') {if (ch == '-') f = -1; ch = getchar();} while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();} return x * f; } int N, M; pii a[MAXN], b[MAXN], q[MAXN], c[MAXN]; ll f[MAXN]; namespace solution{ ll calc(int x, int y){ ll d1 = (b[y].fi - a[x].fi), d2 = (b[y].se - a[x].se); if (d1 <= 0 || d2 <= 0) return 0; return d1 * d2; } void Work(int le, int ri, int dl, int dr){ int mi = (le + ri) >> 1, dm = le; f[mi] = 0; up (i, dl, dr) if (calc(i, mi) > f[mi]) { f[mi] = calc(i, mi); dm = i; } if (le <= mi - 1) Work(le, mi - 1, dl, dm); if (mi + 1 <= ri) Work(mi + 1, ri, dm, dr); } void Prepare(){ N = read(); M = read(); up (i, 1, N) { a[i].fi = read(); a[i].se = read(); } up (i, 1, M) { b[i].fi = read(); b[i].se = read(); } sort(a + 1, a + N + 1); sort(b + 1, b + M + 1); int top = 0; q[++top] = a[1]; up (i, 2, N) if (a[i].fi != q[top].fi && a[i].se < q[top].se) q[++top] = a[i]; up (i, 1, top) a[i] = q[i]; N = top; top = 0; up (i, 1, M) { while (top && b[i].se >= q[top].se) top--; q[++top] = b[i]; } up (i, 1, top) b[i] = q[i]; M = top; int cur = 0; top = 0; int mn = oo; up (i, 1, M) { while (cur + 1 <= N && a[cur + 1].fi < b[i].fi) { cur++; cmin(mn, a[cur].se); } if (mn < b[i].se) q[++top] = b[i]; } M = top; up (i, 1, top) b[i] = q[i]; } void Solve(){ Work(1, M, 1, N); ll ans = 0; up (i, 1, M) cmax(ans, f[i]); printf("%lldn", ans); } } int main(){ using namespace solution; Prepare(); Solve(); return 0; }
原文:大专栏 「World Final 2017」Money for Nothing
来源:博客园
作者:大君君
链接:https://www.cnblogs.com/dajunjun/p/11651737.html