「World Final 2017」Money for Nothing

匿名 (未验证) 提交于 2019-12-03 00:14:01

首先考虑暴力做法,$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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!