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

题解:P13754 【MX-X17-T3】Distraction_逆序对_前缀和_Ad-hoc_算法竞赛C++

Beginning

这道题思维难度很大,有两个难点其实都不好解决,但因为其代码太过弱智所以只是绿题。

本题解详细地分析了做题时的历程与思路,所以希望大家可以仔细地完整阅读。

Analysis

首先先大体观察一下题目的性质:nnn 是排列,这可能会有用;题目的权值求法其实就是逆序对,而逆序对产生的贡献一定有偶数个,所以我们的答案一定是偶数。

同时,对二取模也十分引人注意。这意味着我们的 vvv 序列其实是一个 010101 序列。

题目要求可以选择执行一次移动操作使得权值和变大,也就是我们要通过这一次操作尝试变出更多的 111。尝试一下发现,每次移动一个数只会对其移动中跨过的数产生影响,如果是 010101 序列的话就体现在会把 010101 翻转。对于移动的数字,如果跨过了奇数个位置则翻转,否则不变。

可以简单理解一下:

  1. 如果一个数 xxx 从位置 aaa 移动到位置 bbbb+1b+1b+1 之间(满足 a<ba<ba<b),那么对于 [a+1,b][a+1,b][a+1,b] 中的任意一个数字 ttt,如果 xxx 在移动前对 ttt 产生了贡献,则 x>tx>tx>t,移动后 xxx 将不再对 ttt 产生贡献,在模二的意义下就相当于 ttt 异或上 111,即 010101 翻转。反之亦然。
  2. 对于 xxx 同理,其移动后原来产生贡献的数字一定不产生贡献,原来不产生贡献的数字一定会产生新贡献。看贡献变化量的奇偶性,如果跨过偶数个那么贡献变化量一定是偶数(偶数 - 偶数 = 偶数),在模二意义下贡献值不变。反之亦然。

我们好像得到了一个初步的简化题面:给定一个 010101 序列,可以翻转某一个区间,使得最终序列中 111 个数最多。

显然,我们要求一个类似最大子段和的东西,然后用初始贡献加上一次翻转能带来的最大贡献就是答案。

同时我们还发现翻转区间的长度只能是偶数,因为上述 xxx 跨过奇数个位置的情况下 xxx 自己也会变,其实就等价于翻转了 [a,b][a,b][a,b] 这个长度为偶数的区间。

所以我们要找到一个长度为偶数的区间使得区间内 000 的个数减去 111 的个数得到的差最大。

考虑把 000 映射成 111,把 111 映射成 −1-11,然后统计前缀和。对于每个位置,可以记录下之前奇数位置与偶数位置上的最小前缀和,根据下标奇偶性转移最大差值即可。

时间复杂度 O(n)O(n)O(n)


这还没完,转换完题意后我们还要考虑如何计算初始贡献。这道题时限卡树状数组的 log⁡\loglog(实测光放一个 sort 交上去就会 TLE),所以我们还要考虑如何线性求初始贡献。

肯定要从对二取模这个性质下手。发现我们最开始得到的逆序对贡献数一定是偶数这个结论其实很对,假设对于 pip_ipi,因为是排列所以比 pip_ipi 小的数就有 pi−1p_i-1pi1 个。设 tit_iti 表示 iii 左边比 pip_ipi 小的数的个数,根据题目贡献可以写成 [(i−1)−ti]+[(pi−1)−ti]=i+pi−(2ti+2)[(i-1)-t_i]+[(p_i-1)-t_i] = i+p_i - (2t_i+2)[(i1)ti]+[(pi1)ti]=i+pi(2ti+2),后半部分明显被取模二约掉了!所以最终的初始贡献表达式即为 vi=(i+pi) mod 2v_i=(i+p_i) \bmod 2vi=(i+pi)mod2

根据上述方法预处理即可,时间复杂度 O(n)O(n)O(n)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e6 + 7;int n, a[maxn], s[maxn];void solve()
{int ans = 0;cin >> n;for(int i = 1; i <= n; i ++){cin >> a[i];a[i] = (i + a[i]) % 2; // 计算初始值ans += (a[i] == 1); // 统计答案s[i] = s[i - 1] + (a[i] == 0? 1 : -1); // 转化+预处理前缀和}int min1 = 1e9, min2 = 0; // 奇数、偶数位置的最小前缀和int maxd = 0; // 最大贡献for(int i = 1; i <= n; i ++){if(i % 2 == 0){maxd = max(maxd, s[i] - (i==2? 0:min2)); // 特判一下之前还没有前缀和的时候可以认为能全选(历史前缀和=0)min2 = min(min2, s[i]);}else{maxd = max(maxd, s[i] - (i==1? 0:min1));min1 = min(min1, s[i]);}}cout << ans + maxd << '\n';
}signed main()
{ios :: sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int T; cin >> T;while(T --) solve();return 0;
}
http://www.dtcms.com/a/347915.html

相关文章:

  • GECP高程控制点数据集进行展示
  • 视觉革命:云渲染如何让创意不再受限于硬件
  • RustFS的边缘计算优化方案在5G MEC场景下的实测数据如何?
  • 迭代器模式与几个经典的C++实现
  • 双目密集匹配(stereo dense matching)
  • 从人工巡检到智能监测:工业设备管理的颠覆性变革
  • 97. 小明逛公园,Floyd 算法,127. 骑士的攻击,A * 算法
  • [Redis进阶]---------持久化
  • std::uncaught_exceptions 详解
  • 大模型——深度评测智能体平台Coze Studio
  • 【Cmake】cmake_minimum_required,project,include,install,add_executable
  • 关于链式二叉树的几道OJ题目
  • 【Java SE】抽象类与Object类
  • 什么是正态分布
  • Mysql InnoDB 底层架构设计、功能、原理、源码系列合集【五、InnoDB 高阶机制与实战调优】
  • Manus AI 与多语言手写识别技术文章大纲
  • 夜间跌倒漏报率↓78%!陌讯多模态算法在智慧养老院的精准监测方案
  • Python 地理空间分析:核心库与学习路线图
  • 【三维重建】第二章 Python及Pytorch基础
  • 关于说明锂电池充电芯片实际应用
  • Python Excel
  • C++项目实战——高性能内存池(四)
  • Nacos-11--Nacos热更新的原理
  • 循环中的阻塞风险与异步线程解法
  • 综合测验:配置主dns,dhcp,虚拟主机,nfs文件共享等
  • 操作系统知识
  • (一)算法(big O/)
  • claude-code+kimi实测
  • 当AI成了“历史笔迹翻译官”:Manus AI如何破解多语言手写文献的“密码锁”
  • Redis优缺点