1 条题解
-
0
E. Increasing Frequency 题解(完整整合版)
一、题目描述
时间限制: 2秒
内存限制: 256 MB给定一个长度为 的数组 。你可以选择一个子段 ()和一个整数 (可以为正数、负数或零),然后对该子段中的每个元素加上 (即对于每个 ,令 )。
问:经过一次这样的操作后,数组中值为 的元素最多能有多少个?
输入
第一行包含两个整数 和 (,)——数组长度以及目标值 。
第二行包含 个整数 ()——数组 。
输出
输出一个整数——经过上述操作后,值为 的元素的最大可能数量。
样例
样例 1
输入: 6 9 9 9 9 9 9 9 输出: 6样例 2
输入: 3 2 6 2 6 输出: 2提示
- 样例 1:选择任意子段并取 ,数组保持不变。
- 样例 2:选择子段 并取 ,数组变为 。
二、核心思路
问题转化
对于某个值 ,若我们选择 ,则操作区间内:
- 原本等于 的元素会变成 → 收益
- 原本等于 的元素会变成 → 损失
- 其他值不受影响,忽略
因此,对每个 ,问题转化为:
找一个区间,最大化区间内
v 的个数 - c 的个数。最终答案:
$$\text{ans} = (\text{原数组中 } c \text{ 的总数}) + \max_{v \neq c}\Big(\max_{\text{区间}} (cnt_v - cnt_c)\Big) $$括号内部至少为 (可取 ,什么也不做)。
Kadane 算法(最大子段和)
上述内层是经典的最大子段和问题:把 看作 , 看作 ,求最大连续子段和。
int maxSegment(const vector<int>& s) { int mx = -INF; int bal = 0; for (int i = 0; i < sz(s); i++) { bal = max(0, bal + s[i]); // 若前缀和变负则丢弃 mx = max(mx, bal); } return mx; }时间复杂度 。
高效构建序列
对每个 显式构建完整 序列再跑 Kadane 是 的,不可行。
优化: 利用 的前缀和数组
cntC,将相邻 之间夹着的所有 合并为一个权值为 的元素。这样每个 的序列长度与其出现次数成正比,总长度 。构建过程:
- 预处理 的前缀和
cntC[i]= 前 个元素中 的个数。 - 遍历数组,用
lst[v]记录值 上一次出现的位置。 - 对当前 :
- 压入 上一次 到当前位置之间的 数量
- 压入 (当前 )
- 遍历结束后对每个 补上最后一段到末尾的 数量。
三、AC 代码
#include <bits/stdc++.h> using namespace std; const int INF = int(1e9); int n, c; vector<int> a; vector<int> cntC; int getCnt(int l, int r) { return cntC[r] - cntC[l]; } int maxSegment(const vector<int>& s) { int mx = -INF; int bal = 0; for (int i = 0; i < (int)s.size(); i++) { bal = max(0, bal + s[i]); mx = max(mx, bal); } return mx; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> c; a.resize(n); for (int i = 0; i < n; i++) cin >> a[i]; cntC.assign(n + 1, 0); for (int i = 0; i < n; i++) cntC[i + 1] = cntC[i] + (a[i] == c); int cntDif = *max_element(a.begin(), a.end()) + 1; vector<vector<int>> segs(cntDif); vector<int> lst(cntDif, -1); for (int i = 0; i < n; i++) { segs[a[i]].push_back(-getCnt(lst[a[i]] + 1, i)); lst[a[i]] = i; segs[a[i]].push_back(1); } for (int v = 0; v < cntDif; v++) segs[v].push_back(-getCnt(lst[v] + 1, n)); int ans = 0; for (int v = 0; v < cntDif; v++) { if (v == c) continue; ans = max(ans, maxSegment(segs[v])); } cout << cntC[n] + ans << "\n"; return 0; }
四、复杂度分析
- 时间复杂度: 。构建序列总长度 ,所有 Kadane 总时间 。
- 空间复杂度: 。
- 1
信息
- ID
- 6758
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者