【2022 省选训练赛 Contest 18 A】B(Splay)

B

题目链接:2022 省选训练赛 Contest 18 A

题目大意

给你 n 个点,每个点第 i 天的代价是 b[i]+(i-1)a[i]。
然后要你在前 m 天每天选一个点,然后最小化总代价。

思路

首先考虑怎么 DP,观察到如果你选好的一个点集,你可以很容易的得到最优的选的方案。
即按 ai 从大到小排,然后每次依次选,这样增长的量就会最小。

我们可以按 ai 从大到小排序来 DP,设 fi,j 为搞定前 i 个,选了 j 个的最小费用。
然后每次下一个选或者不选转移,显然超时。
考虑维护每个 fi 数组,亦或者说是看一个新的数会产生什么。

然后有一些性质。
首先就是 fi,j 的点集必定是 fi,j+1 点集的子集,你可以用反证法来得到。
(反正意思就是你不选这个点集的肯定不如 fi,j 的点集加上一个数更优)

然后接着就是加入一个数,它能修改的范围一定是一段后缀。
这个也是可以通过反证法得到,根据前面的性质就有了。

那我们就可以通过二分出贡献的后缀。
然后你要支持区间插入,区间加,区间二分,可以用平衡树来实现。
(过程就是维护每个点当前代表的选的个数,以及新选这个需要的费用)

(那你贡献就是一个区间加值,就是后面的一段都要加上你这个 ai,因为你每往后一个位置,就多了 ai 的费用)

代码

#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC target("avx") #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-fwhole-program") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-fstrict-overflow") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-skip-blocks") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("-funsafe-loop-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int N = 1e6 + 100; struct node { ll a, b; }a[N]; int n, k, rt; ll ans; ll re; char c; ll read() { re = 0; c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') { re = (re << 3) + (re << 1) + c - '0'; c = getchar(); } return re; } bool cmp(node x, node y) { return x.a > y.a; } ll clac(int x, ll k) { return (k - 1) * a[x].a + a[x].b; } struct SPLAY { int tot, pl[N], ls[N], rs[N], lzyp[N], fa[N]; ll val[N], lzyv[N]; bool lrs(int x) {return ls[fa[x]] == x;} int newpoint(int x, ll k) { int now = ++tot; val[now] = k; pl[now] = x; return now; } void downv(int x, ll va) { val[x] += va; lzyv[x] += va; } void downp(int x, int p) { pl[x] += p; lzyp[x] += p; } void down(int now) { if (lzyv[now]) { if (ls[now]) downv(ls[now], lzyv[now]); if (rs[now]) downv(rs[now], lzyv[now]); lzyv[now] = 0; } if (lzyp[now]) { if (ls[now]) downp(ls[now], lzyp[now]); if (rs[now]) downp(rs[now], lzyp[now]); lzyp[now] = 0; } } void rotate(int x) { int y = fa[x], z = fa[y]; int b = lrs(x) ? rs[x] : ls[x]; if (z) (lrs(y) ? ls[z] : rs[z]) = x; if (lrs(x)) rs[x] = y, ls[y] = b; else ls[x] = y, rs[y] = b; fa[x] = z; fa[y] = x; if (b) fa[b] = y; } void Splay(int x) { while (fa[x]) { if (fa[fa[x]]) { if (lrs(x) == lrs(fa[x])) rotate(fa[x]); else rotate(x); } rotate(x); } rt = x; } int get(int p) { int now = rt, re = p; while (now) { down(now); if (val[now] < clac(p, pl[now])) now = rs[now]; else re = pl[now], now = ls[now]; } return re; } void insert(int x) { int now = rt; while (1) { down(now); int tmp = pl[now] < pl[x] ? rs[now] : ls[now]; if (!tmp) { (pl[now] < pl[x] ? rs[now] : ls[now]) = x; fa[x] = now; break; } else { now = tmp; } } Splay(x); } void count(int now) { if (pl[now] <= k) ans += val[now]; down(now); if (ls[now]) count(ls[now]); if (rs[now]) count(rs[now]); } }T; int main() { n = read(); k = read(); for (int i = 1; i <= n; i++) a[i] = (node){read(), read()}; sort(a + 1, a + n + 1, cmp); rt = T.newpoint(1, clac(1, 1)); for (int i = 2; i <= n; i++) { int pl = T.get(i); T.insert(T.newpoint(pl, clac(i, pl))); if (T.rs[rt]) { T.downp(T.rs[rt], 1); T.downv(T.rs[rt], a[i].a); } } T.count(rt); printf("%lld", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/16056911.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示