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;
}

posted @ 2021-02-22 15:01  _int_me  阅读(50)  评论(0编辑  收藏  举报