[决策单调性] [数据结构] AT_joisc2019_j ケーキの貼り合わせ (Cake 3)
posted on 2024-05-24 05:58:46 | under | source
硬想是想不出来滴。考虑 \(n=m\) 的特殊情况。
式子的前半部分不变,要令后半部分最小,不难得到贪心策略:从小到大放。这样子代价是 \(2(\max b-\min b)\),容易证明这是下界。可以尝试改变下位置,你会发现怎么改都不能更优。
注意到后半部分中,我们只关心最大和最小蛋糕,中间的与 \(2(\max b-\min b)\) 没有直接关联。
将蛋糕按 \(b\) 从小到大排,对每个 \(i\) 求出 \(f_i=\max\limits_{1\le j<i}(a_i+a_j-2(b_i-b_j)+w(j+1,i-1))\)。
其中,\(w(l,r)\) 表示 \([l,r]\) 中选取前 \(m-2\) 个最大的 \(a\) 的价值。离散化后,用可持久化权值线段树即可 \(O(\log n)\) 得出。
虽然它不满足四边形不等式,但打表发现 \(f\) 具有决策单调性。
证明:若在 \(i\) 时决策点 \(x<y\) 且 \(x\) 更优,证明在 \(i+1\) 时 \(x\) 还是更优即可。
将相同项去掉,我们有 \(a_x+2b_x+w(x+1,i-1)\ge a_y+2b_y+w(y+1,i-1)\)。
着重关注 \(w\) 部分,注意到一个关键性质:\(w(x+1,i)\) 的增长速度一定比 \(w(y+1,i)\) 快。这不难感性理解,因为前者元素总体更小,被替换的原元素也更小,差值就更大。
于是有 \(w(x+1,i+1)-w(x+1,i) \ge w(y+1,i+1)-w(y+1,i)\)。
与原不等式相加,就可得知决策点 \(x\) 在 \(i+1\) 时仍然更优。证毕。
分治实现即可,复杂度 \(O(n\log^2n)\)。
代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
#define int long long
#define mid (l + r >> 1)
const int N = 2e5 + 5, inf = -1e15;
int n, _n, m, ans, idw[N], f[N];
struct node{int _a, _b;} a[N];
inline bool cmp(node A, node B) {return A._b < B._b;}
inline bool cmpp(int A, int B) {return A > B;}
namespace Zx_Tree{
struct node{int ls, rs, s, siz;} t[N * 30];
int rot[N], tot;
inline void psup(int u) {t[u].s = t[t[u].ls].s + t[t[u].rs].s, t[u].siz = t[t[u].ls].siz + t[t[u].rs].siz;}
inline int S(int x, int y) {return t[y].s - t[x].s;}
inline int Siz(int x, int y) {return t[y].siz - t[x].siz;}
inline void upd(int ua, int &ub, int l, int r, int k, int p){
t[ub = ++tot] = t[ua];
if(l == r) {t[ub].s += p, ++t[ub].siz; return ;}
if(k <= mid) upd(t[ua].ls, t[ub].ls, l, mid, k, p);
else upd(t[ua].rs, t[ub].rs, mid + 1, r, k, p);
psup(ub);
}
inline int qry(int ua, int ub, int l, int r, int p){
if(Siz(ua, ub) <= p) return S(ua, ub);
if(l == r) return p * idw[l];
if(Siz(t[ua].rs, t[ub].rs) >= p) return qry(t[ua].rs, t[ub].rs, mid + 1, r, p);
else return S(t[ua].rs, t[ub].rs) + qry(t[ua].ls, t[ub].ls, l, mid, p - Siz(t[ua].rs, t[ub].rs));
}
}using namespace Zx_Tree;
inline int w(int x, int y) {return qry(rot[x - 1], rot[y], 1, n, m - 2);}
inline void calc(int l, int r, int kl, int kr){
if(l > r || kl > kr) return ;
int k = kl;
for(int p = kl; p <= min(mid - m + 1, kr); ++p){
int W = idw[a[mid]._a] + idw[a[p]._a] + w(p + 1, mid - 1) - (a[mid]._b - a[p]._b);
if(W >= f[mid]) f[mid] = W, k = p;
}
calc(l, mid - 1, kl, k), calc(mid + 1, r, k, kr);
}
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; ++i) scanf("%lld%lld", &a[i]._a, &a[i]._b), a[i]._b <<= 1;
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= n; ++i) idw[i] = a[i]._a, f[i] = inf;
sort(idw + 1, idw + 1 + n), _n = unique(idw + 1, idw + 1 + n) - idw - 1;
for(int i = 1; i <= n; ++i) a[i]._a = lower_bound(idw + 1, idw + 1 + _n, a[i]._a) - idw;
for(int i = 1; i <= n; ++i) upd(rot[i - 1], rot[i], 1, n, a[i]._a, idw[a[i]._a]);
calc(1, n, 1, n);
ans = inf; for(int i = 1; i <= n; ++i) ans = max(ans, f[i]);
cout << ans;
return 0;
}

浙公网安备 33010602011771号