[CF2057F] Formation 做题记录

news/2025/1/9 20:59:53/文章来源:https://www.cnblogs.com/Sktn0089/p/18662891

link

对我比较有意义的一道题目。

我们先逐步分析,对于单个询问,先钦定最大值位置 \(i\),我们现在的目标是最大化 \(a_i\) 的值。

这显然有单调性,考虑二分一个 \(mid\) 表示最终值,那么会出现一个 \(l(l\le i)\) 以及一个序列 \(c_{0\dots l - 1}\)\(c_i = \lceil \dfrac {mid} {2^i}\rceil\)

  • \(\forall j \in [0, l - 1], \ a_{i - j} \le c_j\)

  • \(l = i\)\(a_{i - l} \ge c_j\)

  • 代价为 \(\sum\limits_{j = 0} ^ {l - 1} (c_j - a_{i - j})\)

注意到若固定一个 \(l\)\(mid\) 的合法取值形如一个区间。此时把代价式子拆开 \(\sum\limits_{j = 0} ^ {l - 1} c_j - \sum\limits_{j = 0} ^ {l - 1} a_{i - j}\),只分别和 \(mid\)\(i\) 有关。

固定 \(l\),枚举 \(i\),我们会得到若干个三元组 \((l, r, w)\),表示一个 \(mid\) 取值区间以及其代价常数(即是 \(\sum\limits_{j = 0} ^ {l - 1} a_{i - j}\))。这 \(n\) 个区间将数轴分成了若干段,每段求出覆盖它的区间的最大代价常数。这样,每次询问一个 \(mid\),只需要二分出 \(mid\) 在哪一段即可。

这样即可 \(\mathcal O(\log ^ 2 V \log n)\) 求出一个询问的答案。

考虑 \(q\) 个询问,尝试优化到 \(2\log\)。发现唯一能优化的点在于二分查找 \(mid\) 所属哪一段,考虑将所有询问一起二分,将所有 \(mid\) 和这 \(\mathcal O(n)\) 段一起双指针,时间复杂度 \(\mathcal O(q\log ^ 2 V)\)

  • 启示:这题先二分,从枚举 \(i\) 转为枚举 \(l\),说明暴力是通往正解的必要途径,也体现了转置思想的重要性(更换枚举对象)。然后固定 \(l\),处理出 \(\mathcal O(n)\) 段,这一步我根本没有想到,原因在于我只从常规的数据结构以及其他知识结构出发,忽略了整理信息这一方向。最后是类似整体二分的 trick。
点击查看代码
#include <bits/stdc++.h>namespace Initial {#define ll long long#define ull unsigned long long#define fi first#define se second#define mkp make_pair#define pir pair <ll, ll>#define pb push_back#define i128 __int128using namespace std;const ll maxn = 1e5 + 10, inf = 1e18, mod = 998244353;ll power(ll a, ll b = mod - 2, ll p = mod) {ll s = 1;while(b) {if(b & 1) s = 1ll * s * a %p;a = 1ll * a * a %p, b >>= 1;} return s;}template <class T>const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }template <class T>const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }template <class T>const inline void chkmax(T &x, const T y) { x = x < y? y : x; }template <class T>const inline void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;namespace Read {char buf[1 << 22], *p1, *p2;// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)template <class T>const inline void rd(T &x) {char ch; bool neg = 0;while(!isdigit(ch = getchar()))if(ch == '-') neg = 1;x = ch - '0';while(isdigit(ch = getchar()))x = (x << 1) + (x << 3) + ch - '0';if(neg) x = -x;}
} using Read::rd;ll t, n, q, a[maxn], c[maxn], id[maxn];
ll lo[maxn], hi[maxn], mid[maxn], cst[maxn];
vector <pair <pir, ll> > _vec[maxn];
vector <pir> vc[maxn], vec[maxn];
ll h[maxn], ht; multiset <ll> st;ll calc(ll x, ll l) {ll tmp = (x >> l) << l;ll ret = (tmp << 1) - (tmp >> l - 1);tmp = x & ((1 << l) - 1);ret += (tmp << 1) - __builtin_popcount(tmp);if(tmp) {tmp = __builtin_ctz(tmp);ret += l - tmp - 1;} return ret;
}void solve() {rd(n), rd(q);for(ll i = 1; i <= n; i++) rd(a[i]);for(ll l = 1; l <= 30; l++) vec[l].clear(), _vec[l].clear();for(ll i = 1; i <= n; i++) {ll low = 0;for(ll l = 1, sum = 0; l <= i && l <= 30; l++) {chkmax(low, a[i - l + 1] << l - 1);ll high = i == l? inf : a[i - l] << l;sum += a[i - l + 1], _vec[l].pb(mkp(mkp(low, high), sum));}}for(ll l = 1; l <= 30; l++) {if(_vec[l].empty()) {vec[l].pb(mkp(inf, -inf)); continue;}sort(_vec[l].begin(), _vec[l].end()); ht = 0;for(auto t: _vec[l]) h[++ht] = t.fi.fi, h[++ht] = t.fi.se + 1;sort(h + 1, h + 1 + ht);ht = unique(h + 1, h + 1 + ht) - h - 1;for(ll i = 1; i <= ht; i++) vc[i].clear();for(auto t: _vec[l]) {ll x = lower_bound(h + 1, h + 1 + ht, t.fi.fi) - h,y = upper_bound(h + 1, h + 1 + ht, t.fi.se) - h;vc[x].pb(mkp(t.se, 1)), vc[y].pb(mkp(t.se, 0));} st.clear(); h[ht + 1] = inf + 5;if(h[1] > 1) vec[l].pb(mkp(h[1] - 1, -inf));for(ll i = 1; i <= ht; i++) {for(pir t: vc[i])if(t.se) st.insert(t.fi);else st.erase(st.find(t.fi));vec[l].pb(mkp(h[i + 1] - 1, st.empty()? -inf : *st.rbegin()));}}for(ll i = 1; i <= q; i++) rd(c[id[i] = i]);sort(id + 1, id + 1 + q, [](ll i, ll j) {return c[i] < c[j];});ll kc = 0;for(ll i = 1; i <= n; i++) chkmax(kc, a[i]);for(ll i = 1; i <= q; i++) lo[i] = kc, hi[i] = 2e9;for(ll o = 0; o <= 30; o++) {for(ll i = 1; i <= q; i++) mid[i] = lo[i] + hi[i] >> 1, cst[i] = inf;for(ll l = 1; l <= 30; l++) {// if(l == 2 && o == 30)// 	puts("GC");for(ll i = 0, j = 0; i < vec[l].size(); i++) {while(j < q && mid[id[j + 1]] <= vec[l][i].fi) {ll k = id[++j];chkmin(cst[k], calc(mid[k], l) - vec[l][i].se);}}}for(ll i = 1; i <= q; i++)if(cst[i] <= c[i]) lo[i] = mid[i] + 1;else hi[i] = mid[i] - 1;// printf("%lld %lld\n", l, res[1]);}for(ll i = 1; i <= q; i++) printf("%lld ", hi[i]); puts("");
}int main() {rd(t); while(t--) solve();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/866743.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java] 计算Java对象大小

序在Java应用程序的性能优化场景中,时常需要考虑Java对象的大小,以便评估后,进一步提出优化方案:占用内存的大小。(比如 本地内存) 对象数据在网络传输中占用的网络带宽 对象数据在存储时占用的磁盘空间 ...概述 对象大小如何计算对象大小包括俩部分的内容,对象头和对象…

并行前缀(Parallel Prefix)加法器

并行前缀(Parallel Prefix)加法器 并行前缀加法器的基本介绍 二进制加法器是目前数字计算单元中的重要模块,基础的加法器架构包括行波进位加法器(Ripple Carry Adder),超前进位加法器(Carry Look-Ahead Adder),进位选择加法器(Carry Select Adder)等。加法器的进位传…

科技风?写实风?教你设置多风格三维地图

概述 三维地图通过高度、深度、立体感等表现形式,能够真实还原地形地貌、城市建筑和空间结构。相比二维地图,它能够更清晰地展示复杂的地理数据,帮助用户快速理解空间关系,如地形起伏、建筑高度等。在实际应用中,我们可以将不同风格的三维地图作为项目的主体元素进行展示,…

【模拟电子技术】03-PN与二极管的特性

【模拟电子技术】03-PN与二极管的特性上节中有提到对PN结施加反向电压时,会使得PN结所形成的势垒增加,阻止多子到另一边。在掺杂浓度比较低的时候,外加电场加强,中间的耗尽层会加长,变成了一个粒子加速器,自由电子进去后不断加速。直到某一电场强度时,粒子加速足够大的时…

NocoBase 本周更新汇总:支持大规模数据量的导入和导出

本周更新包括:支持大规模数据量的导入和导出等。汇总一周产品更新日志,最新发布可以前往我们的博客查看。 NocoBase 目前更新包括的版本更新包括三个分支:main ,next和 develop。main :截止目前最稳定的版本,推荐安装此版本。 next:包含即将发布的新功能,经过初步测试的…

MSSQL:DBLINK连接oracle 19

无法为该请求检索数据。(Microsoft.SqlServer.Management.Sdk.Sfc)其他信息:执行Transact-SQL语句或批处理时发生了异常。(Microsoft.SqlServer.ConnectionInfo)在与SQL Server 建立连接时出现与网络相关的特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正…

五款强大报表软件助力企业提升数据分析效率

本文将为大家介绍五款功能强大的报表软件,包括山海鲸报表、JReport、Power BI、Zoho Analytics 和 SAP Crystal Reports。这些工具各具特色,能够帮助企业快速生成数据报表并进行深度分析。无论是数据可视化、报表定制、自动化生成还是与其他系统的集成,它们都能为企业的决策…

Linq中的设置操作 (C#):Distinct 和 DistinctBy、Except 和 ExceptBy、Intersect 和 IntersectBy、Union 和 UnionBy

LINQ 中的集运算是指根据相同或单独集合中是否存在等效元素来生成结果集的查询运算。 注:这些示例使用 System.Collections.Generic.IEnumerable<T> 数据源。 基于 System.Linq.IQueryProvider 的数据源使用 System.Linq.IQueryable<T> 数据源和表达式树。 表达式…

2025多校冲刺省选模拟赛3

过于困难,直接放弃2025多校冲刺省选模拟赛3\(T1\) A. 等差 \(100pts/100pts\)考虑哈希,每 \(k\) 个作为一组与上一组统一计算。取 \(Base>\) 值域时用高精度来存储并判断的正确性显然。观察到可行的最小的 \(k\) 单调不降,不妨直接枚举答案。暴力实现时间复杂度为 \(O(n…

还不会 Cert Manager 自动签发证书?一文掌握

相信很多小伙伴对于 Cert Manager 不陌生,Cert Manager 是 Kubernetes 上的证书管理工具,基于 ACME 协议与 Lets Encrypt 签发免费证书并为证书自动续期,实现永久免费使用证书。 本文将介绍如何使用 Cert Manager 实现自动签发证书并与 Rainbond 结合使用。 Cert Manager 概…

JAVA-Day 09:While循环语句

While循环 while循环格式 初始化语句; while(条件判断语句){ 循环体语句; 条件控制语句; } 初始化语句只执行一次 判断语句为True,循环继续 判断语句为False,循环结束 例: 世界最高山峰珠穆朗玛峰的高度为8844.43米=8844430毫米,假如有 一张足够大的纸,它的厚度为0.1毫米。…

rust学习十六.2、并发-利用消息传递进行线程间通讯

通过信道是rust的解决线程之间通信的2个工具之一,另外1个是是共享内存状态。 rust推出这个,明显地是因为受到go之类的影响。 在书籍中,作者提到go编程文档中的内容: 不要通过共享内存来通讯;而是通过通讯来共享内存(Do not communicate by sharing memory; instead, share…