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

题解: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.xdnf.cn/news/18563.html

相关文章:

  • java猜数字游戏(赌城主题版)
  • priority_queue和仿函数
  • 【CSP初赛】程序阅读3
  • (一)算法(big O/)
  • 一种解决使用 PotPlayer 播放 Alist 的 Webdav 时提示 无法在 FTP/WebDAV/HTTP 上修改该文件夹 的方法
  • QT-Mysql-查询语句-查询是否有表-表列名-查询记录
  • 【AI基础:神经网络】16、神经网络的生理学根基:从人脑结构到AI架构,揭秘道法自然的智能密码
  • TensorFlow 深度学习 开发环境搭建
  • Java和数据库的关系
  • Ubuntu 的 apt-get 强制使用 IPv4 网络
  • How to Use Managed Identity with ACS?
  • XCVU13P-2FHGB2104E Xilinx(AMD)Virtex UltraScale+ FPGA
  • MySQL索引原理与优化全解析
  • 55.Redis搭建主从架构
  • ANSI终端色彩控制知识散播(II):封装的层次(Python)——不同的逻辑“一样”的预期
  • 【C初阶】自定义类型--结构体
  • Java:对象的浅拷贝与深拷贝
  • 探索 List 的奥秘:自己动手写一个 STL List✨
  • 基于JSqlParser的SQL语句分析与处理
  • 网址账号正确,密码错误返回的状态码是多少
  • Go语言数据结构与算法-基础数据结构
  • Compose笔记(四十七)--SnackbarHost
  • Axure:有个特别实用的功能
  • 什么是AI宠物
  • [2025CVPR-目标检测方向]PointSR:用于无人机视图物体检测的自正则化点监控
  • C++的struct里面可以放函数,讨论一下C++和C关于struct的使用区别
  • leetcode算法刷题的第十六天
  • 力扣热题之技巧
  • 雷卯针对香橙派Orange Pi 3G-IoT-B开发板防雷防静电方案
  • 云原生、容器及数据中心网络相关名词记录