The 2nd Universal Cup. Stage 3: Binjiang L. Partially Free Meal
提供一个常数小且好写的做法。
首先对于序列按照
首先递归右区间,这样右边的答案已经处理好了,考虑如何与左边的合并。
此时由于右区间有选择点,那么
那么问题变为,给定两个序列:
后面是个
有了这个性质,考察
在每个区间更新的时候再用一个分治来做决策单调性得到
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mkp make_pair
#define pii pair<int,int>
#define vc vector
#define pb emplace_back
const int N = 2e5 + 5;
const ll inf = 0x3f3f3f3f3f3f3f3f;
inline int read() {
int x = 0, w = 0; char ch = getchar(); while(!isdigit(ch)) w |= (ch=='-'), ch = getchar();
while(isdigit(ch)) x = (x*10)+(ch^48), ch=getchar(); return w?-x:x;
}
int n;
pii a[N];
ll f[N], g[N], dp[N], lf, lg, ldp;
inline void merge(int l, int r, int L, int R) {
int mid = l + r >> 1, p = -1; dp[mid] = inf;
for(int i = L, j = mid - L; i <= R; i++, j--) if(j >= 0 && j <= lg && g[j] + f[i] < dp[mid])
dp[mid] = g[j] + f[i], p = i;
if(l < r) merge(l, mid, L, p), merge(mid + 1, r, p, R);
}
inline vc<ll> solve(int l, int r) {
if(l == r) {
vc<ll> res(2); res[1] = a[l].first + a[l].second;
return res;
}
int mid = l + r >> 1;
auto R = solve(mid + 1, r); lf = R.size() - 1; g[lg = 0] = 0;
for(int i = 0; i <= lf; i++) f[i] = R[i];
for(int i = l; i <= mid; i++) g[++lg] = a[i].second;
sort(g + 1, g + 1 + lg);
for(int i = 1; i <= lg; i++) g[i] += g[i - 1];
merge(1, ldp = r - l + 1, 1, lf);
vc<ll> res(ldp + 1, 0);
for(int i = 0; i <= ldp; i++) res[i] = dp[i];
auto L = solve(l, mid);
for(int i = 0; i < L.size(); i++) res[i] = min(res[i], L[i]);
return res;
}
signed main() {
n = read();
for(int i = 1; i <= n; i++) a[i].second = read(), a[i].first = read();
sort(a + 1, a + 1 + n);
auto ans = solve(1, n);
for(int i = 1; i <= n; i++) printf("%lld\n", ans[i]);
return 0;
}