「Gym 104901F」Say Hello to the Future

news/2025/10/27 17:04:37/文章来源:https://www.cnblogs.com/keysky/p/19169602

题目大意

给定一个序列,定义其权值为划分序列的方案数,使得划分出来的每个区间 \([l, r]\)\(\max_{i = l}^r {a_i} \leq r - l + 1\) 。对于每个 \(1 \leq i \leq n\) 求只将 \(a_i\) 修改为 \(1\) ,序列的权值。

做法详解

首先我们先想一想假如不修改 \(a_i\) 怎么做。对于这种序列划分的问题一般来说都是线性dp ,这道题也不例外,令 \(dp_i\) 表示划分 \([1, i]\) 的方案数,暴力转移显然有

\[dp_i = \sum_{j = 1}^{i} dp_{j - 1} \times [\max_{k = j}^i {a_k} \leq i - j + 1] \]

当我们考虑转移时发现限制转移的状态不连续,没有单调性,十分难处理,所以考虑dp中的暴力优化——CDQ分治优化。

对于 \([l, r]\) ,我们从 \([l, mid]\)\([mid + 1, r]\) 转移,那么我们首先要处理原本的区间最大值,由于转移一定是会跨过 \(mid\) 从左向右,那么我们可以维护 \([l, mid]\) 的后缀最大值数组 \(lmx\)\([mid + 1, r]\) 的前缀最大值数组 \(rmx\),那么我们转移条件就变成了 \(max\{ lmx_j, rmx_i \} \leq i - j + 1\) ,拆分一下有

\[i - j + 1 \geq lmx_j \\ i - j + 1 \geq rmx_i \]

移项

\[i \geq lmx_j + j - 1 \\ i - rmx_i \geq j - 1 \]

我们发现两个式子左边只跟 \(i\) 有关,右边只跟 \(j\) 有关,所以将 \([l, mid]\)\(lmx_j + j - 1\) 排序,然后双指针保证第一个式子,将 \(j - 1\) 拍到树状数组上,对于 \(i\) 查询树状数组 \([1, i - rmx_i]\) 的和,加到 \(dp_i\) 上。

现在不带修改做完了,我们想想带修改的怎么做。我们发现将 \(a_i\) 修改为 \(1\) 相当于是将 \(i\) 的限制给消削掉了,所以答案中每一种方案一定包含什么都不改的序列的划分方案,所以我们考虑增加了那些方案。

首先我们不可能将 \(a_i\) 改了后再跑一遍dp(这不废话),同时对于划分序列正着dp倒着dp没有影响,\(i\) 也只包含与一个区间,所以我们可以预处理两个dp数组 \(f_i\)\(g_i\) 分别表示 \([1, i]\) 的划分方案数和 \([i, n]\) 的划分方案数。

那么增加的方案显然有 \(\sum_{l = 1}^i \sum_{r = i}^n f_{l - 1} g_{r + 1} \times [\max_{j = l}^r \{ a_j \} = a_i > r - l + 1 \wedge \text{secondmax}_{j = l}^r \{ a_j \} \leq r - l + 1]\)

同样,这个条件很难直接做,我们就把其扔到CDQ里面考虑。对于 \([l, r]\) ,我们依照预处理dp那样维护 \(lmx\)\(rmx\) ,再额外维护 \(selmx\)\(sermx\) ,以及 \(p_i\) 表示 \(i\) 的前缀/后缀最大值位置。考虑枚举 \(l/r\)(以 \(r\) 为例),首先,我们可以肯定的是当前所算出的方案数增加量是加在 \(p_r\) 的答案上的,然后,因为我们要同时保证 \(a_{p_i} > r - l + 1 \wedge \text{secondmax}_{j = l}^r \{ a_j \} \leq r - l + 1\) ,如果我们把 \(r - rmx_r \geq l - 1\) 拉出来排序那就需要跑两遍,还要加到同一个计算点上@#!%&#@*……总之,就是S上加S,所以我们把 \(r \geq lmx_l + l - 1\) 拉出来排序,然后将 \(l - 1\) 拍到树状数组上,权值为 \(f_{l - 1}\),查询时就可以简单地查询树状数组上 \((r - rmx_r, r - sermx_r]\) 的和,加到 \(ans_{p_r}\) 上即可。

就这样

for (int i = mid + 1, j = l;i <= r;++i) {while (j <= mid && lmx[id[j]] + id[j] <= i + 1) {BIT.change(id[j], f[id[j] - 1]);stk[++top] = id[j];++j;}trans(ans[p[i]], (BIT.query(i - rsemx[i] + 1) - BIT.query(i - rmx[i] + 1) + mod) * g[i + 1] % mod);
}

Solution

代码和讲的有些 \(+1\)\(-1\) 的位置不一样,读者移下项就可以发现于解法中狮子是一样的。

还有代码输入输出跟本题有些不同,因为笔者是在另一个地方做的,见谅。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
const int mod = 998244353;
int n, q;
int a[N];
LL f[N], g[N];
#define lowbit(x) (x & -x)
inline void trans(LL& x, LL y) { x = (x + y) % mod; }
struct BinaryTree {LL c[N << 1];inline void change(int x, LL k) { for (;x <= n + 1;x += lowbit(x)) trans(c[x], k); }inline void clean(int x) { for (;x <= n + 1;x += lowbit(x)) c[x] = 0; }inline LL query(int x) {LL ret = 0;for (;x > 0;x -= lowbit(x)) trans(ret, c[x]);return ret;}
}BIT;
int id[N], lmx[N], rmx[N], lsemx[N], rsemx[N], p[N];
inline void reset(int l, int r) { for (int i = l;i <= r;++i) id[i] = i; }
inline bool cmp(int i, int j) { return lmx[i] + i < lmx[j] + j; }
inline bool cmp2(int i, int j) { return i - rmx[i] + 1 < j - rmx[j] + 1; }
int stk[N], top;
inline void solve(int l, int r, LL* dp) {if (l == r) {if (a[l] == 1) trans(dp[l], dp[l - 1]);return;}int mid = l + r >> 1;solve(l, mid, dp);lmx[mid] = a[mid];for (int i = mid - 1;i >= l;--i) lmx[i] = max(lmx[i + 1], a[i]);rmx[mid + 1] = a[mid + 1];for (int i = mid + 2;i <= r;++i) rmx[i] = max(rmx[i - 1], a[i]);sort(id + l, id + mid + 1, cmp);for (int i = mid + 1, j = l;i <= r;++i) {while (j <= mid && lmx[id[j]] + id[j] <= i + 1) {BIT.change(id[j], dp[id[j] - 1]);stk[++top] = id[j];++j;}trans(dp[i], BIT.query(i - rmx[i] + 1));}reset(l, mid);while (top > 0) BIT.clean(stk[top--]);solve(mid + 1, r, dp);
}
LL ans[N], d[N];
inline void solve2(int l, int r) {if (l == r) return trans(ans[l], (a[l] > 1) * f[l - 1] * g[l + 1]);int mid = l + r >> 1;solve2(l, mid);solve2(mid + 1, r);lmx[mid] = a[mid];lsemx[mid] = 0;p[mid] = mid;for (int i = mid - 1;i >= l;--i) {lmx[i] = lmx[i + 1], lsemx[i] = lsemx[i + 1];p[i] = p[i + 1];if (a[i] > lmx[i]) lsemx[i] = lmx[i], lmx[i] = a[i], p[i] = i;else if (a[i] > lsemx[i]) lsemx[i] = a[i];}rmx[mid + 1] = a[mid + 1];p[mid + 1] = mid + 1;rsemx[mid + 1] = 0;for (int i = mid + 2;i <= r;++i) {rmx[i] = rmx[i - 1], rsemx[i] = rsemx[i - 1];p[i] = p[i - 1];if (a[i] > rmx[i]) rsemx[i] = rmx[i], rmx[i] = a[i], p[i] = i;else if (a[i] > rsemx[i]) rsemx[i] = a[i];}sort(id + l, id + mid + 1, cmp);for (int i = mid + 1, j = l;i <= r;++i) {while (j <= mid && lmx[id[j]] + id[j] <= i + 1) {BIT.change(id[j], f[id[j] - 1]);stk[++top] = id[j];++j;}trans(ans[p[i]], (BIT.query(i - rsemx[i] + 1) - BIT.query(i - rmx[i] + 1) + mod) * g[i + 1] % mod);}reset(l, mid);while (top > 0) BIT.clean(stk[top--]);sort(id + mid + 1, id + r + 1, cmp2);for (int i = mid, j = r;i >= l;--i) {while (j > mid && id[j] - rmx[id[j]] + 1 >= i) {BIT.change(id[j] + 1, g[id[j] + 1]);stk[++top] = id[j] + 1;--j;}trans(ans[p[i]], ((BIT.query(n + 1) - BIT.query(i + lsemx[i] - 1) + mod) - (BIT.query(n + 1) - BIT.query(i + lmx[i] - 1)) + mod) * f[i - 1] % mod);}reset(mid + 1, r);while (top > 0) BIT.clean(stk[top--]);
}
int main() {freopen("divide.in", "r", stdin);freopen("divide.out", "w", stdout);scanf("%d%d", &n, &q);for (int i = 1;i <= n;++i) scanf("%d", &a[i]);for (int i = 1;i <= n;++i) id[i] = i;f[0] = g[0] = 1;solve(1, n, f);for (int i = 1;i <= n;++i) trans(ans[i], f[n]);reverse(a + 1, a + n + 1);solve(1, n, g);reverse(a + 1, a + n + 1);reverse(g + 1, g + n + 1);g[n + 1] = 1;solve2(1, n);while (q--) {int x;scanf("%d", &x);printf("%lld\n", ans[x]);}return 0;
}

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

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

相关文章

渐进过程中大O与小o混用

在数学中,大O符号(O)和小o符号(o)都用于描述函数的渐进行为,但它们的含义和强度不同。在实际使用中,需要注意它们的定义和适用场景,以避免误用。 \(O(x)\) 表示一个函数的渐进上界。具体来说,如果存在正常数C…

Navicat 17 超详细保姆级下载安装教程:附激活工具使用步骤​

这篇教程给你讲的Navicat 17安装方法,从下载到激活一步不落,中间碰到问题也能帮你解决,跟着做保准能装好。​这篇教程给你讲的Navicat 17安装方法,从下载到激活一步不落,中间碰到问题也能帮你解决,跟着做保准能装…

消息队列的有序性

RabbitMQ单一队列和单一消费者模式:确保一个队列只被一个消费者消费,这样可以保证消息按照发送的顺序被处理。因为队列本身就是一个先进先出的结构。 消息排序:在消息生产者端,为消息添加序列号和时间戳,消费者根…

【LTDC】DMA2D —— 嵌入式系统的 GPU

前言 ST 公司设计了一个专门用于图像处理的 DMA:DMA2D,可以之际通过 DMA2D 搬运或填充图像,而不经过 CPU,极大减轻了 CPU 的负担。为了学习 DMA2D,我也专门写了这篇文章,现在就让我们来看看吧! DMA2D 工作模式 …

各个版本的sqlite-jdbc jar下载链接

https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc

[电脑]win10下SVN图标不显示

[电脑]win10下SVN图标不显示转自 : https://blog.csdn.net/qq_43331089/article/details/128876896win10系统的SVN图标不现实了。正常情况下,会在文件夹上有一个对勾 但是对勾以及所有的SVN图标都突然消失了,都不知道…

2025/10/27~2025/11/2 做题笔记 - sb

2025/10/27 第一代图灵机 一样的套路,考虑每一个右端点对应的最左边可以到哪里,显然是最小的 \(j\) 使得 \(\max\limits_{j \le k \le i}pre_k = j - 1\)。考虑线段树维护一个区间内的最大的答案和最大的 \(pre_i\),…

echart - f

series: [{name: "直接访问",type: "bar",// 修改柱子宽度barWidth: "35%",data: [200, 300, 300, 900, 1500, 1200, 600],itemStyle: {// 修改柱子圆角barBorderRadius: 5}}]series中的…

完整教程:LinuxC++——etcd分布式键值存储系统入门

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

基于MATLAB的光学CCD全息成像仿真程序实现

基于MATLAB的光学CCD全息成像仿真程序实现一、流程 graph TD A[物光生成] --> B[参考光干涉] B --> C[全息图记录] C --> D[CCD光电转换] D --> E[电荷转移] E --> F[噪声注入] F --> G[信号重建]二…

el-date-picker样式修改

el-date-picker样式修改模板<el-col :span="12"><div class="detail-row flex-row"><span class="detail-label"><span style="color: red;margin-right: 4p…

我从哪里起飞 从哪里降落 多少不能原谅的错 却不能重来过

10.27 CF1988F Heartbeat P10440 [JOIST 2024] 环岛旅行 / Island Hopping P10439 [JOIST 2024] 逃生路线 2 / Escape Route 2

unity管理器设计:Manager of Managers

一、管理器Manager Manager管理器是对一类对象进行统一管理,像是UIManager,AudioManager,InputManager等。 UIManager对UI的生命周期进行统一管理,AudioManager对音频的播放进行统一管理,InputManager对玩家的输入…

iview table 排序 columns 里面写 sortable: custom 不要写 sortable: true 不然会进行二次内部排序序号等 字段。

iview table 排序 columns 里面写 sortable: custom 不要写 sortable: true 不然会进行二次内部排序序号等 字段。--------------------------------------------- 生活的意义就是你自己知道你要做什么,明确目标。没有…

决策不再凭感觉!Tita用数据驱动销售与交付的一体化协同

在当今激烈的市场竞争中,企业高层管理者们正面临一个普遍而棘手的难题:销售目标设定明确,但执行过程却总是脱节;客户信息散落在各个销售人员的Excel表和笔记本中,难以形成有效的客户洞察;销售过程缺乏透明化管控…

浅谈 Agent 开发工具链演进历程

模型带来了意识和自主性,但在输出结果的确定性和一致性上降低了。无论是基础大模型厂商,还是提供开发工具链和运行保障的厂家,本质都是希望提升输出的可靠性,只是不同的团队基因和行业判断,提供了不同的实现路径。…

为IvorySQL增添PACKAGE语法帮助

认识语法帮助 当使用psql工具登录数据库时,\h command可以查看语法帮助。比如查看create database语法: psql (17.6) Type "help" for help.ivorysql=# \h create database Command: CREATE DATABASE …

MATLAB 时间序列小波周期分析

1. 文件结构 WaveletPeriod/ ├── main_wavelet_period.m % 一键运行 ├── wavelet_power_spectrum.m % 小波功率谱 + 显著性 ├── period_peak_detect.m % 自动周期峰值 ├── plot_wavelet_results.m …

# 情绪日历应用(python AI项目)

📖 项目简介 这是一个基于人脸情绪识别的智能日历应用,能够:📅 记录你每天的情绪状态 😊 自动识别照片中的情绪 💬 提供情绪陪伴聊天 📊 统计月度情绪变化🏗️ 代码结构详解 1. 导入模块部分 - 程序的&q…

读《程序员修炼之道:从小工到专家》

读《程序员修炼之道》,仍被书中 “务实的程序员” 理念戳中。它没教复杂算法,却把成长拆成可落地的日常:像 “ DRY 原则” 让我改掉重复写工具类的习惯,“不要重复发明轮子” 提醒我先调研再动手,而 “持续学习”…