当前位置: 首页 > news >正文

20250921 模拟赛 T4 题解

Description

https://zhengruioi.com/problem/3343?cid=1976

Solution

容易发现区间 LIS 满足四边形不等式,所以最终的答案关于划分段数是凸的。

\(d_i=f_i-f_{i-1}\)。那么由于 \(\sum d_i=n\)\(d_i\) 不增,所以 \(d_i\) 只有 \(O(\sqrt n)\) 种取值。

于是就只需要求出 \(g_k\) 表示 \(d_i\geq k\) 的最大的 \(i\),这个 \(g_k\) 也只有 \(O(\sqrt n)\) 种取值。

求单点的 \(g_k\) 的做法是设一个区间的贡献是 LIS 减 \(k\),然后再对一个 pair 进行 dp,这个 pair 的含义是 {最大权值,最大段数}。

对于所有的 \(g_k\) 考虑分治求,假设现在需要求出 \([l,r]\)\(g_k\) 值,先暴力求出 \(g_{mid}\) 的值 \(v\),如果 \(v=g_{l-1}\) 就说明 \([l,mid-1]\) 全是 \(v\),直接赋值,否则继续递归。对于右区间同理。

可以证明只需要求 \(O(\sqrt n)\) 次单点 \(g_k\) 的值。

时间复杂度:\(O(n\sqrt n\log n)\)

Code

#include <bits/stdc++.h>// #define int int64_tusing pii = std::pair<int, int>;const int kMaxN = 1.5e5 + 5;int cid, n;
int a[kMaxN], d[kMaxN], res[kMaxN];
int ct;template<class T> inline void chkmax(T &x, T y) { x = (x > y ? x : y); }
template<class T> inline void chkmin(T &x, T y) { x = (x < y ? x : y); }struct BIT {pii c[kMaxN];void clear() { std::fill_n(c + 1, n + 1, pii{-1e9, 0}); }void upd(int x, pii v) {for (; x <= n + 1; x += x & -x) chkmax(c[x], v);}pii qry(int x) {pii ret = {-1e9, 0};for (; x; x -= x & -x) chkmax(ret, c[x]);return ret;}
} bit;int get(int k) {static pii f[kMaxN];bit.clear();bit.upd(n + 1, {0, 0});++ct;pii mx = {0, 0};for (int i = 1; i <= n; ++i) {pii v1 = mx, v2 = bit.qry(a[i] - 1);v1.first += 1 - k, ++v1.second, ++v2.first;bit.upd(a[i], f[i] = std::max(v1, v2));chkmax(mx, f[i]);}return bit.qry(n + 1).second;
}void solve(int l, int r, int vl, int vr) {if (l > r) return;int mid = (l + r) >> 1, val = get(mid);d[mid] = val;if (val == vl) {for (int i = l; i < mid; ++i) d[i] = val;} else {solve(l, mid - 1, vl, val);}if (val == vr) {for (int i = mid + 1; i <= r; ++i) d[i] = val;} else {solve(mid + 1, r, val, vr);}
}void dickdreamer() {std::cin >> n;for (int i = 1; i <= n; ++i) std::cin >> a[i];d[0] = n, d[n + 1] = 0;// std::cerr << get(1) << '\n';ct = 0;solve(1, n, n, 0);for (int i = n; ~i; --i) {for (int j = d[i + 1] + 1; j <= d[i]; ++j)res[j] = res[j - 1] + i;}for (int i = 1; i <= n; ++i) std::cout << res[i] << " \n"[i == n];// for (int i = 0; i <= n + 1; ++i) std::cerr << d[i] << " \n"[i == n + 1];
}int32_t main() {freopen("lis.in", "r", stdin);freopen("lis.out", "w", stdout);std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);int T = 1;std::cin >> cid >> T;while (T--) dickdreamer();// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";return 0;
}
http://www.hskmm.com/?act=detail&tid=12091

相关文章:

  • 1.3 课前问题列表
  • NOIP 模拟赛十一
  • Proxy 库解析(四)
  • warm-flow 监听器对象获取问题
  • Hexo Butterfly 5.4 分页问题 YAML 错误 解决方法总结
  • js逆向:某Q音乐平台请求数据模拟生成
  • maven
  • 第十一届中国大学生程序设计竞赛网络预选赛(CCPC Online 2025)
  • 网络流
  • 完整教程:数据结构 栈和队列、树
  • 深入解析:【ubuntu】ubuntu中找不到串口设备问题排查
  • 酵母双杂交技术:高通量筛选的突破与不可忽视的三大局限性
  • ubuntu20.04测试cuda
  • Android Studio 配置国内源
  • PyCharm项目上传GitHub仓库(笔记) - 教程
  • 从RAG出发
  • 软件工程第二次作业——第一次个人编程作业
  • Ubuntu 24.04 安装 DaVinci Resolve
  • Promise中处理请求超时问题
  • 图解26:老生常谈的OSI网络模型
  • 【C++】指针
  • AI驱动建筑行业数字化转型
  • 详细介绍:前端学习——CSS
  • VSCode 把代码发送到激活状态下的终端
  • 线性结构之数组[基于郝斌课程]
  • 完整教程:Vue中的props方式
  • 图解25:MySQL主从复制原理
  • 用 Go 编写验证码识别脚本(基于 Tesseract)
  • 软工第二次作业
  • Zero-Shot、One-Shot、Few-Shot概念