CodeForces 1082E Increasing Frequency 计数 递推 思维
题意
-
给我们一个长为n的序列A以及一个整数c,对这个序列的任何一个连续区间[l, r],我们可以给这个区间内的数统一加上一个我们任取的整数k。
-
要求我们只能做上述操作一次,问最终序列内最多有多少个c
思路
-
首先这个序列里面可能本来就有一些c,我们定义\(cnt[i]\)为前i个数内的c的个数
-
然后对于我们选择的一段区间\([l, r]\), 我们选取其中的某个数x,然后让这个区间同加c - x, 那么得到的c的个数就是x在这个区间的的出现次数。
-
然后我们考虑,如果我们将\([l, r]\)内的x都变成c, 则最终整个序列内的c的数量就是
\[cnt[n] - cnt[r] + cnt[l - 1] + 区间内x的数量 \]我们的任务也就是求出上式的最大值
-
我们考虑递推解决这个问题,前三个量都可以预处理出来,但是当我们扫描到\(i\)位置,某个区间\([l, i]\)内x的数量不好求出,因为元素的值域是\([1, 5e5]\)的,所以肯定不能像\(cnt\)数组那样求。
-
解决方法也比较简单,我们定义\(cntx[i]\)为前i个数中,\(A[i]\)的数量,然后我们可以发现,扫描到i位置时,我们只需要处理\(A[i]\)相关的信息即可,也就是说,我们只需要统计区间\([l, i](l \le i)\)中\(A[i]\)的数量即可(毕竟其他数都在之前被处理过了), 所以边扫描边更新就可以了。
-
那如何获得某个区间内x的数量呢,这个要从我们之前的目的开始考虑,对于我们所要求的式子
\[max_{l \le i}\{cnt[n] - cnt[i] + cnt[l - 1] + [l, i]内A[i]的数量\} \]也就是
\[max_{l \le i}\{cnt[n] - cnt[i] + cnt[l - 1] + [0, i]内A[i]的数量 - [0, l - 1]内A[i]的数量\} \]当我们在\(i\)位置时, 有三项和\(i\)有关的为已知的定值,有两项和\(l\)有关,所以我们实际要求的是
\[cnt[n] - cnt[i] + cntx[i] + max_{l \le i}\{cnt[l - 1] - [0, l - 1]内A[i]的数量\} \]
- 显然我们使用一个数组\(Maxl[A[i]]\), 扫描的同时记录\(max_{l \le i}\{cnt[l - 1] - [0, l - 1]内A[i]的数量\}\)就可以了,然后扫描过程中先更新\(Maxl\),然后更新\(ans\)即可
AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 500000;
int mx[N + 5];
int cn[N + 5];
int xn[N + 5] = {0};
int aa[N + 5];
int n, c;
int main()
{
scanf("%d%d", &n, &c);
cn[0] = 0;
xn[0] = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &aa[i]);;
cn[i] = cn[i - 1] + (aa[i] == c);
}
int ans = 0;
for (int i = 1; i <= n; ++i)
{
++xn[aa[i]];
mx[aa[i]] = max(mx[aa[i]], cn[i - 1] - xn[aa[i]] + 1);
ans = max(cn[n] - cn[i] + xn[aa[i]] + mx[aa[i]], ans);
}
printf("%d", ans);;
return 0;
}