20250808 模拟赛
并非码力,并非模拟
题目描述
给定一个 n×mn×m 的二元矩阵,11 表示黑色单元格,00 表示白色单元格。每一秒,每个黑色单元格会将其上、下、左、右四个相邻的白色单元格染成黑色。
你可以 最多 将一个白色单元格变成黑色(将 00 变成 11),以最小化整个矩阵完全变黑所需要的时间,求出这个最短时间。
文件读入:color.in
文件读写:color.out
一种O(n)的check方法 目前很快
首先将所有初始黑色单元格 (‘1’) 同时入队,计算每个单元格到最近黑色点的最小曼哈顿距离 dist[i][j]。 然后二分答案 二分时间T,难点在于如何check check就是判断是否存在一个白色或任意单元 (x,y) 使得对所有 dist[i][j]>T 的点,都有 |x−i|+|y−j| ≤ T
n^2check很唐,所以对绝对值分讨
i+j−T≤x+y≤i+j+T
i−j−T≤x−y≤i−j+T
所以对于所有白色的点,我们记录 u_min = max(i + j - T)
u_max = min(i + j + T)
v_min = max(i - j - T)
v_max = min(i - j + T)
最后 我们要判断: 是否存在一个整数点 (x, y),使得 (u = x + y) 和 (v = x - y) 都落在对应的范围内? x 与 y 需要为整数,x = (u + v)/2, y = (u - v)/2 这意味着u 和 v 必须具有相同奇偶性(即 (u + v) 与 (u - v) 都是偶数)
我们检查 [u_min, u_max] 与 [v_min, v_max] 这两个区间中是否有某一对整数 u, v 有相同奇偶性即可。
问题描述
阿斯凯拉德(Askeladd)是维京海盗的领袖,他们正在寻找宝藏。在袭击了一个村庄后,他们收集了 nn 个宝藏,按顺序排列,价值分别为 a1,a2,…,ana1,a2,…,an。
团队有一个协议:作为领袖,阿斯凯拉德将获得前 kk 个宝藏(价值为 a1,a2,…,aka1,a2,…,ak),其余的海盗将分配剩下的宝藏。然而,由于时间已晚,分配被推迟到第二天早上。
阿斯凯拉德很狡猾,他秘密地试图在夜间重新排列宝藏,以获得更多的总价值。他只能交换两个相邻的宝藏。每次交换的成本为 cc 价值,因为存在被其他海盗发现的风险。阿斯凯拉德可以执行任意次数的交换(包括零次)。
阿斯凯拉德想要找到他能获得的最大利润,定义为:他获得的宝藏总价值减去交换的总成本。
文件读入:treasure.in
文件读写:treasure.out
我们钦定p1...pk表示选的,要把这k个弄到前k各位置的坐标。
那么答案就是
发现后面-j可以直接提出来,变成
前面直接对于每个p = i算然后排序取k大即可。
对于一个长度为 LL(LL 为奇数) 的数组 aa,定义它的中位数 median(a)median(a) 为 aa 中第 L+122L+1 大的数。
现在给你一个长度为 nn 的排列,对于每对满足 1≤i≤j≤1≤i≤j≤ 并且 j−i≡0j−i≡0 (mod(mod 2)2) 的 (i,j)(i,j),你需要计算 i×j×median(p[i...j])i×j×median(p[i...j])
输出所有值的总和。
文件读入:median.in
文件读写:median.out
下面给出一个基于「把每个值 m 当作中位数来统计」的 O(n²) 做法思路。核心思想是:
- 
枚举中位数值 m
由于 p 是 1…n 的排列,中位数一定落在这些值里,我们对 m 从 1 到 n 遍历。 - 
找到 m 在数组中的位置 pos
任何一个奇长子段要以 m 为中位数,子段必须包含 pos,且该子段中比 m 小的数和比 m 大的数个数相同。 - 
构造左右前缀平衡数组
定义一个映射\[ b[i] = \begin{cases} +1, & p[i] > m,\\ -1, & p[i] < m,\\ 0, & i = pos. \end{cases} \]那么对于任何包含 pos 的子段 [i…j],它以 m 为中位数等价于
\[ \sum_{t=i}^j b[t] = 0. \]我们把这个和拆成 “左半段” 和 “右半段”:
- 左半段的前缀和:\(s_L(k)=\sum_{t=k}^{pos-1}b[t]\),对应子段左端点 i=k+1。
 - 右半段的前缀和:\(s_R(k)=\sum_{t=pos+1}^{k}b[t]\),对应子段右端点 j=k.
 
 - 
按平衡值配对并加权
记左边所有可能的 \((\Delta=s_L,\ \text{parity of }i)\) 统计为\[ \text{cntL}[\Delta][\pi] = \sum_{\substack{i\le pos\\i\equiv \pi\bmod2}}1,\quad \text{sumL}[\Delta][\pi] = \sum_{\substack{i\le pos\\i\equiv \pi\bmod2}}i \]同理右边有 \(\text{cntR},\ \text{sumR}\)(按 j 的奇偶分组),
只有当左端 i 和右端 j 同奇偶,且平衡值相等 \(\Delta_L=\Delta_R\) 时,子段 [i…j] 才会是奇长且满足总和为 0。
因此对每个平衡值 \(\Delta\) 和奇偶 \(\pi\in\{0,1\}\):\[ \sum_{i,j}i\cdot j = \bigl(\text{sumL}[\Delta][\pi]\bigr)\times\bigl(\text{sumR}[\Delta][\pi]\bigr). \]把所有平衡值、两种奇偶情况累加,再乘上当前中位数 m,就得到了所有以 m 作中位数的子段贡献:
\[ \text{contrib}(m) = m \;\times\;\sum_{\Delta,\pi}\bigl(\text{sumL}[\Delta][\pi]\bigr)\times\bigl(\text{sumR}[\Delta][\pi]\bigr). \] - 
时间复杂度
对每个 m 我们在 O(n) 时间里扫一遍左右前缀并维护哈希表,合并统计也 O(n)(平衡值种类上限 2n+1)。总体 O(n)×n = O(n²)。 
小结
- 利用「把每个元素当候选中位数」的「前缀和 + 哈希配对」思路,省去了每段插入、求第 k 大的 log 因子;
 - 通过「左边、右边统计 (i, j) 同奇偶且平衡值相等」来保证子段为奇长且中位数恰好是 m;
 - 最终在 O(n²) 内完成所有测试用例的计算。
 
给你一个长度为 nn 的排列,你需要从中选出一个最长的子序列(注意是子序列不是子串),满足该子序列中两端的值大于中间的所有值。
输出子序列的最大长度。
文件读入:sequence.in
文件读写:sequence.out
下面给出一个 \(O(n\log n)\) 的做法,思路分三步:
一、预处理后缀最左/最右出现位置
记原排列为 \(a[1\ldots n]\),并且预先建立一个数组
对于每个阈值 \(T\)(我们把“端点最小值”记为 \(T\)),我们需要知道所有值 \(\ge T\) 在序列中出现的最左和最右位置:
// 初始化:
L[n+1] = +∞;   R[n+1] = −∞;
// 逆序维护:
for T = n, n−1, …, 1:
    L[T] = min( L[T+1], pos[T] )
    R[T] = max( R[T+1], pos[T] )
这样,对任意阈值 \(T\),区间 \([L[T],\,R[T]]\) 恰好囊括了所有值 ≥ \(T\)。
二、离线统计“小于 T”的元素个数
对于固定 \(T\),在子序列中,中间元素必须严格小于 \(T\),且它们的位置在 \((L[T],\,R[T])\) 之间。设
那么以两端点取任意两个 \(\ge T\) 的位置为端点,能取得的最长子序列长度至多
为了 离线 高效算出 \(\text{small}_T\),我们按值从小到大“开闸放水”——把所有值 \(<T\) 的位置依次插入一个长度为 \(n\) 的 Fenwick 树(BIT),用来维护“哪些位置是小于当前阈值的”。
- 
初始时,BIT 全 0;
 - 
当我们将某个值 \(v\)(从 1 到 \(n\))“放入”时,就在
pos[v]处做 +1 操作; - 
在放入之前,BIT 上恰好存储了「所有值 < \(T\) 的位置」;于是即可在 \(O(\log n)\) 内回答区间 \([L[T],R[T]]\) 中有多少个小于 \(T\):
small_T = BIT.query(R[T]−1) − BIT.query(L[T])(因为两端点本身都是 ≥T,不算入中间)
 
                    
                
                
            
        
浙公网安备 33010602011771号