Codeforces 1082E - Increasing Frequency - 动态规划
题解链接
题目链接
https://codeforces.com/contest/1082/problem/E
题目
You are given array a a a of length n n n. You can choose one segment [ l , r ] [l, r] [l,r] ( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1≤l≤r≤n) and integer value k k k (positive, negative or even zero) and change a l , a l + 1 , … , a r a_l, a_{l + 1}, \dots, a_r al,al+1,…,ar by k k k each (i.e. a i : = a i + k a_i := a_i + k ai:=ai+k for each l ≤ i ≤ r l \le i \le r l≤i≤r).
What is the maximum possible number of elements with value c c c that can be obtained after one such operation?
题意
有 n n n个元素,第 i i i个元素的值为 a i a_i ai,你可以选择一个区间 [ l , r ] [l, r] [l,r],并将这个区间的每个元素都加上 k k k( k k k为任意值,包括负数),问你在最多修改一次的情况下,能让这个序列中最多存在几个值为 c c c的元素。
思路
考虑我们将区间 [ l , r ] [l, r] [l,r]中所有的 x x x都修改为 c c c,则只需让这个区间中的每一个元素都加上 c − x c - x c−x,此时区间中所有的 x x x都会变为 c c c,而 c c c则变成了非 c c c的值。
记 s u m i sum_i sumi为区间 [ 1 , i ] [1, i] [1,i]中有多少个元素的值为 c c c,记 c n t i cnt_i cnti为区间 [ 1 , i ] [1, i] [1,i]中有多少个元素的值为 x x x。
则我们修改某个区间 [ l , r ] [l, r] [l,r]中的 x x x的时候,整个序列中 c c c的个数由 s u m n sum_n sumn变为了 s u m l − 1 + c n t r − c n t l − 1 + s u m n − s u m r sum_{l - 1} + cnt_r - cnt_{l - 1} + sum_n - sum_r suml−1+cntr−cntl−1+sumn−sumr。
而我需要对于每一个区间都求一个这样的答案,然后取最大值,即: m a x { s u m l − 1 + c n t r − c n t l − 1 + s u m n − s u m r } ( 1 ≤ l ≤ r ≤ n ) max\{sum_{l - 1} + cnt_r - cnt_{l - 1} + sum_n - sum_r\}\ (1 \leq l \leq r \leq n) max{suml−1+cntr−cntl−1+sumn−sumr} (1≤l≤r≤n)。
注意到对于每一个固定的 r r r, c n t r cnt_r cntr、 s u m n sum_n sumn、 s u m r sum_r sumr均为定值,问题就转化成为对于每一个 r r r,求 m a x { s u m l − 1 − c n t l − 1 } ( 1 ≤ l ≤ r ) max\{sum_{l - 1} - cnt_{l - 1}\}\ (1 \leq l \leq r) max{suml−1−cntl−1} (1≤l≤r),这样以来就可以 O ( n ) O(n) O(n)进行 D P DP DP了。
实现
#include <bits/stdc++.h>
const int maxn = int(5e5) + 7;
std::map<int, std::vector<int>> map;
int n, c, sum[maxn], a[maxn], cnt[maxn];
int main() {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
sum[i] = sum[i - 1] + (a[i] == c);
map[a[i]].push_back(i);
}
int ans = sum[n];
for (auto cur : map) {
const std::vector<int> &vector = cur.second;
int num = cur.first, max = 0;
for (const auto &pos : vector) {
max = std::max(max, sum[pos - 1] - cnt[num]++);
ans = std::max(ans, cnt[num] - sum[pos] + max + sum[n]);
}
}
printf("%d\n", ans);
return 0;
}