【大联盟】20230703 T2 开心的序列(sequence) 题解 AT_agc049_f 【[AGC049F] Happy Sequence】

zak /bx

恐怖 zak 将这题加强,出到模拟赛。直接把 Ai,Bi105,Ci5 变成了 Ai,Bi,Ci109

非常恐怖。

题目描述#

点击膜拜 zhoukangyang

题解#

重新再理解一遍。

我们维护 p(x)=i|aix|+|bix|,那么就相当于要求 x,p(x)0,也就是 pmax0

继续观察下。首先,显然需要满足 iai=ibi,我们设这个数为 S。那么,对于 x,p(x)0 的限制,我们设 ca<xai 个数、sa<xai 的和、cbsb 同理。

于是就得出,x,(Ssa)x(nca)+xcasa(Ssb)x(ncb)+xcbsb,化简可得 xcasaxcbsb,也就是要求 max{xcasa(xcbsb)}0

考虑 max 取在哪?一定是在 ca=cb 的位置,因为若 ca<cb,则 x+1 一定更优,若 ca>cb,则 x1 一定更优。

所以,我们只需要关注 ca=cb 的位置,于是得出结论:满足条件当且仅当,对于排好序ab,满足 1xn,i=1xaibi0,且 i=1nai=i=1nbi

我们令 g(x)=i=1xaibi,条件为 g(x)0

这个结论赛时猜结论打表也发现了,不过完全没想到后面的。


我们发现:

  • ai 增加 1,就相当于给 xaip(x) 都增加 1,给 x>Aip(x) 都减少 1
  • ai 减少 1,就相当于给 xaip(x) 都增加 1,给 x<Aip(x) 都减少 1

于是,我们观察到让 A 小的数减少 1,并让 A 大的数增加 1,是一定不优的,假设增加的数为 a,减少的数为 b,并满足 a<b,则对于 x<ax>bp(x) 都是不变的,而对于 axbp(x) 却增加了 2

所以,一定存在一个 mid,满足对于 mid 左侧的数都在增加,对于 mid 右侧的数都在减小。如果有多个 mid,取 p(mid) 最大的(假设左侧最右的操作为 l,右侧最左的操作为 r,则 mid(l,r))。

观察到操作后 p(mid)1,因为如果不满足条件,则可以通过删除 左侧第一个操作或右侧第一个操作,这样 p(mid) 就增加 2 了,仍然满足条件还,还更优。

不过,进一步地,由于需要满足 i=1nai=i=1nbi,则说明 p(x) 一定为偶数。因为 p(x)=i=1n(1)[ai>x]+1ai+(1)[ai>x]xi=1n(1)[bi>x]+1bi+(1)[bi>x]x

p(x)i=1nai+xi=1nbi+x(mod2)i=1naii=1nbi(mod2)0(mod2)

所以,可以得到 p(mid)=0

然后,我们发现,由于 mid 左侧的数都在增加,mid 右侧的数都在减小。所以,每次操作都会让 p(mid) 变小,而 p(mid)=0,说明初始时 p(mid) 是最大值。

带入 p(),p()0,可以得到 p()=p()=0,又因为 p(mid)=0,则说明左侧和相等,右侧和相等。

于是,左右就独立了,我们对左右分开做,形式相似(实际上只要把右侧取相反数就跟左侧形式完全一样了)。我们可以二分斜率 M,不过可能出现不合法,那么我们跟上面一样,找到 mid 来处理。

mid 左侧的斜率调整为 [mid,r],右侧调整为 [l,mid],像整体二分一样。

时间复杂度 O(nlogn(logA+logB+logC))

代码#

记录

Copy
#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; }
posted @   zhaohaikun  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
CONTENTS