题解:P12159 [蓝桥杯 2025 省 Java B] 数组翻转
Kato_Shoko · · 题解
蒟蒻的我第一次在洛谷写题解(上一次的寄了),还请多包涵不足的地方。
问题描述。 给定长度为
样例说明。
样例输入:
7
4 4 3 3 2 1 3
翻转区间
关键观察。
翻转操作的唯一作用,是可以将原数组中相同值
若不翻转,则对于值
若允许一次翻转,则对于每个值
算法实现。
- 使用一次从左到右的扫描。
- 令
per[i]表示以位置i 为结尾的、且值相同的最长连续段的长度。 - 当
a_i=a_{i-1} 时,per[i]=per[i-1]+1;否则,表示一段结束,将该段长度per[i-1]记入哈希表mp[a_{i-1}],更新此值的「第一长」和「第二长」;然后重置per[i]=1。 - 扫描结束后,哈希表
mp[v]中存有值为v 的所有连续段的「第一长」f_1 和「第二长」f_2 。对每个键值对(v,(f_1,f_2)) ,计算得分v\times(f_1+f_2) ,取最大。 - 时间复杂度
O(n) ,空间复杂度O(n) (用于存储per数组与哈希表)。
代码如下。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 5;
void solve(){
int n;
cin >> n;
vector<ll> a(n+5), per(n+5);
map<int, pair<ll, ll>> mp;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n + 1; i++) {
if (a[i] == a[i - 1]) {
per[i] = per[i - 1] + 1;
} else {
per[i] = 1;
auto &[firs, seco] = mp[a[i - 1]];
if (per[i - 1] > firs) {
seco = firs;
firs = per[i - 1];
} else {
seco = max(seco, per[i - 1]);
}
}
}
ll ans = 0;
for (auto [x, pa] : mp) {
auto [firs, seco] = pa;
ans = max(ans, x * (firs + seco));
}
cout << ans;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}
复杂度分析。
- 扫描一遍数组维护
per数组与更新哈希表,时间O(n) ; - 最后遍历哈希表键值对,时间
O(m) ,其中m 为不同值的数量,显然m \leq n ,故总时间O(n) 。 - 空间上,
per占O(n) ,哈希表最坏也为O(n) 。
这样就能在