CodeForces 1082E Increasing Frequency 计数 递推 思维

原题链接

题意

  • 给我们一个长为n的序列A以及一个整数c,对这个序列的任何一个连续区间[l, r],我们可以给这个区间内的数统一加上一个我们任取的整数k。

  • 要求我们只能做上述操作一次,问最终序列内最多有多少个c

思路

  • 首先这个序列里面可能本来就有一些c,我们定义 c n t [ i ] cnt[i] cnt[i]为前i个数内的c的个数

  • 然后对于我们选择的一段区间 [ l , r ] [l, r] [l,r], 我们选取其中的某个数x,然后让这个区间同加c - x, 那么得到的c的个数就是x在这个区间的的出现次数。

  • 然后我们考虑,如果我们将 [ l , r ] [l, r] [l,r]内的x都变成c, 则最终整个序列内的c的数量就是

    c n t [ n ] − c n t [ r ] + c n t [ l − 1 ] + 区 间 内 x 的 数 量 cnt[n] - cnt[r] + cnt[l - 1] + 区间内x的数量 cnt[n]cnt[r]+cnt[l1]+x

    我们的任务也就是求出上式的最大值

  • 我们考虑递推解决这个问题,前三个量都可以预处理出来,但是当我们扫描到 i i i位置,某个区间 [ l , i ] [l, i] [l,i]内x的数量不好求出,因为元素的值域是 [ 1 , 5 e 5 ] [1, 5e5] [1,5e5]的,所以肯定不能像 c n t cnt cnt数组那样求。

  • 解决方法也比较简单,我们定义 c n t x [ i ] cntx[i] cntx[i]为前i个数中, A [ i ] A[i] A[i]的数量,然后我们可以发现,扫描到i位置时,我们只需要处理 A [ i ] A[i] A[i]相关的信息即可,也就是说,我们只需要统计区间 [ l , i ] ( l ≤ i ) [l, i](l \le i) [l,i](li) A [ i ] A[i] A[i]的数量即可(毕竟其他数都在之前被处理过了), 所以边扫描边更新就可以了。

  • 那如何获得某个区间内x的数量呢,这个要从我们之前的目的开始考虑,对于我们所要求的式子

    m a x l ≤ i { c n t [ n ] − c n t [ i ] + c n t [ l − 1 ] + [ l , i ] 内 A [ i ] 的 数 量 } max_{l \le i}\{cnt[n] - cnt[i] + cnt[l - 1] + [l, i]内A[i]的数量\} maxli{cnt[n]cnt[i]+cnt[l1]+[l,i]A[i]}

    也就是

    m a x l ≤ i { c n t [ n ] − c n t [ i ] + c n t [ l − 1 ] + [ 0 , i ] 内 A [ i ] 的 数 量 − [ 0 , l − 1 ] 内 A [ i ] 的 数 量 } max_{l \le i}\{cnt[n] - cnt[i] + cnt[l - 1] + [0, i]内A[i]的数量 - [0, l - 1]内A[i]的数量\} maxli{cnt[n]cnt[i]+cnt[l1]+[0,i]A[i][0,l1]A[i]}

    当我们在 i i i位置时, 有三项和 i i i有关的为已知的定值,有两项和 l l l有关,所以我们实际要求的是

    c n t [ n ] − c n t [ i ] + c n t x [ i ] + m a x l ≤ i { c n t [ l − 1 ] − [ 0 , l − 1 ] 内 A [ i ] 的 数 量 } cnt[n] - cnt[i] + cntx[i] + max_{l \le i}\{cnt[l - 1] - [0, l - 1]内A[i]的数量\} cnt[n]cnt[i]+cntx[i]+maxli{cnt[l1][0,l1]A[i]}

  • 显然我们使用一个数组 M a x l [ A [ i ] ] Maxl[A[i]] Maxl[A[i]], 扫描的同时记录 m a x l ≤ i { c n t [ l − 1 ] − [ 0 , l − 1 ] 内 A [ i ] 的 数 量 } max_{l \le i}\{cnt[l - 1] - [0, l - 1]内A[i]的数量\} maxli{cnt[l1][0,l1]A[i]}就可以了,然后扫描过程中先更新 M a x l Maxl Maxl,然后更新 a n s ans 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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值