【大联盟】20230703 T2 开心的序列(sequence) 题解 AT_agc049_f 【[AGC049F] Happy Sequence】
zak /bx
恐怖 zak 将这题加强,出到模拟赛。直接把 \(A_i,B_i\le 10^5, C_i\le 5\) 变成了 \(A_i,B_i,C_i\le 10^9\)。
非常恐怖。
题目描述
题解
重新再理解一遍。
我们维护 \(p(x)=\sum_i|a_i-x|+|b_i-x|\),那么就相当于要求 \(\forall x, p(x)\le 0\),也就是 \(p_{\max}\le 0\)。
继续观察下。首先,显然需要满足 \(\sum_{i}a_i=\sum_{i}b_i\),我们设这个数为 \(S\)。那么,对于 \(\forall x, p(x)\le 0\) 的限制,我们设 \(ca\) 为 \(<x\) 的 \(a_i\) 个数、\(sa\) 为 \(<x\) 的 \(a_i\) 的和、\(cb\)、\(sb\) 同理。
于是就得出,\(\forall x,(S-sa)-x(n-ca)+xca-sa\le (S-sb)-x(n-cb)+xcb-sb\),化简可得 \(\forall xca-sa\le xcb-sb\),也就是要求 \(\max\{xca-sa-(xcb-sb)\}\le 0\)。
考虑 \(\max\) 取在哪?一定是在 \(ca=cb\) 的位置,因为若 \(ca<cb\),则 \(x+1\) 一定更优,若 \(ca>cb\),则 \(x-1\) 一定更优。
所以,我们只需要关注 \(ca=cb\) 的位置,于是得出结论:满足条件当且仅当,对于排好序的 \(a\) 和 \(b\),满足 \(\forall 1\le x\le n,\sum_{i=1}^{x}a_i-b_i\ge 0\),且 \(\sum_{i=1}^{n}a_i=\sum_{i=1}^{n}b_i\)。
我们令 \(g(x)=\sum_{i=1}^{x}a_i-b_i\),条件为 \(\forall g(x)\ge 0\)。
这个结论赛时猜结论打表也发现了,不过完全没想到后面的。
我们发现:
- 让 \(a_i\) 增加 \(1\),就相当于给 \(x\le a_i\) 的 \(p(x)\) 都增加 \(1\),给 \(x>A_i\) 的 \(p(x)\) 都减少 \(1\)。
- 让 \(a_i\) 减少 \(1\),就相当于给 \(x\ge a_i\) 的 \(p(x)\) 都增加 \(1\),给 \(x<A_i\) 的 \(p(x)\) 都减少 \(1\)。
于是,我们观察到让 \(A\) 小的数减少 \(1\),并让 \(A\) 大的数增加 \(1\),是一定不优的,假设增加的数为 \(a\),减少的数为 \(b\),并满足 \(a<b\),则对于 \(x< a\) 或 \(x>b\),\(p(x)\) 都是不变的,而对于 \(a\le x\le b\),\(p(x)\) 却增加了 \(2\)。
所以,一定存在一个 \(mid\),满足对于 \(mid\) 左侧的数都在增加,对于 \(mid\) 右侧的数都在减小。如果有多个 \(mid\),取 \(p(mid)\) 最大的(假设左侧最右的操作为 \(l\),右侧最左的操作为 \(r\),则 \(mid\in(l,r)\))。
观察到操作后 \(p(mid)\ge -1\),因为如果不满足条件,则可以通过删除 左侧第一个操作或右侧第一个操作,这样 \(p(mid)\) 就增加 \(2\) 了,仍然满足条件还,还更优。
不过,进一步地,由于需要满足 \(\sum_{i=1}^{n}a_i=\sum_{i=1}^{n}b_i\),则说明 \(p(x)\) 一定为偶数。因为 \(p(x)=\sum_{i=1}^{n}(-1)^{[a_i>x]+1}a_i+(-1)^{[a_i>x]}x-\sum_{i=1}^{n}(-1)^{[b_i>x]+1}b_i+(-1)^{[b_i>x]}x\)。
所以,可以得到 \(p(mid)=0\)。
然后,我们发现,由于 \(mid\) 左侧的数都在增加,\(mid\) 右侧的数都在减小。所以,每次操作都会让 \(p(mid)\) 变小,而 \(p(mid)=0\),说明初始时 \(p(mid)\) 是最大值。
带入 \(p(-\infty),p(\infty)\ge 0\),可以得到 \(p(-\infty)=p(\infty)=0\),又因为 \(p(mid)=0\),则说明左侧和相等,右侧和相等。
于是,左右就独立了,我们对左右分开做,形式相似(实际上只要把右侧取相反数就跟左侧形式完全一样了)。我们可以二分斜率 \(M\),不过可能出现不合法,那么我们跟上面一样,找到 \(mid\) 来处理。
则 \(mid\) 左侧的斜率调整为 \([mid,r]\),右侧调整为 \([l,mid]\),像整体二分一样。
时间复杂度 \(O(n\log n(\log A+\log B+\log C))\)。
代码
记录。
#include <bits/stdc++.h>
#define SZ(x) (int) x.size() - 1
#define all(x) x.begin(), x.end()
#define ms(x, y) memset(x, y, sizeof x)
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> void chkmax(T& x, T y) { x = max(x, y); }
template <typename T> void chkmin(T& x, T y) { x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) { putchar('-'); x *= -1; }
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int N = 2e5 + 10;
int n, b[N], g[N];
struct node {
ll cur;
int beg, val;
friend bool operator < (const node &x, const node &y) {
return x.cur < y.cur;
}
} t[N];
__int128 ans;
void solve(int l, int r, ll L, ll R) {
if (l > r) return;
ll mid = (L + R) >> 1;
F(i, l, r) t[i].cur = t[i].beg + (mid / t[i].val + 1) / 2;
sort(t + l, t + r + 1);
ll s = 0; int pos = r + 1;
DF(i, r, l) {
s += b[i] - t[i].cur;
if (s < 0) {
s = 0;
pos = i;
}
}
if (L + 1 == R) {
__int128 s = 0;
F(i, l, r) {
s += t[i].cur - b[i];
ans += (__int128) (t[i].cur - t[i].beg) * (t[i].cur - t[i].beg) * t[i].val;
} ans -= (__int128) s * R;
return;
} solve(l, pos - 1, mid, R), solve(pos, r, L, mid);
}
signed main() {
// freopen("sequence.in", "r", stdin);
// freopen("sequence.out", "w", stdout);
read(n);
F(i, 1, n) read(t[i].beg), t[i].cur = t[i].beg;
F(i, 1, n) read(b[i]);
sort(b + 1, b + n + 1);
F(i, 1, n) read(t[i].val);
sort(t + 1, t + n + 1);
ll s = 0; int pos = 0;
F(i, 1, n) {
s += t[i].beg - b[i];
if (s < 0) {
s = 0;
pos = i;
}
}
solve(1, pos, 0, 2e18 + 5);
reverse(t + pos + 1, t + n + 1);
reverse(b + pos + 1, b + n + 1);
F(i, pos + 1, n) t[i].beg = 1e9 - t[i].beg, b[i] = 1e9 - b[i];
solve(pos + 1, n, 0, 2e18 + 5);
write(ans);
return 0;
}