Increasing Frequency CodeForces - 1082E(前缀和求子区间最大值方法)

想了一天终于理解了这个题目的思路,

首先我们定义cont(x,l,r)为区间l到r中x出现的次数那么题目中求的就等于=cont(c,1,l-1)+cont(d,l,r)+cont(r+1,n,c)

就是说我们把整个数组分成三段第一段中c的个数加上第二段中我们要改变的d的个数(因为在第二段中如果我们把d变成c,那么肯定要对d做加减操作所以原先在第二段中的c变成不是c所以第二段中没有c)加上第三段中c的个数

然后我们将上述式子化简变成=cont(c,1,n)+cnt(d,l,r)-cnt(c,l,r)就是把整段的c加上第二段中我们把d变成c的个数的d在减掉原本在第二段中c的个数(因为c已经不是c了)然后cont(c,1,n)是一个给定的值所以我们求cnt(d,l,r)-cnt(c,l,r)这个式子的最大值,这个式子的意思就是说在一个区间里d的个数减去c的个数,问题又变成在一个连续区间里求一个子区间的最大值的问题,用到前缀和的方法。

前缀和方法:比如在一个数列1,-2,34,54,-3,5中求一个子区间使得该区间的和是最大值,方法是:先求出每个数的前缀和,然后在遍历数组的时候先求出前缀和的最小值然后答案就变成遍历到该数的前缀和减去最小前缀和在求一个max,这题的方法就是这样只是我们把某数x的出现的个数-c的个数的最小值求出来,然后在减去这个最小值取一个max。

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;


int a[555555]={0};
int min1[555555]={0};

int main()
{
    int n,c;
    cin>>n>>c;
    int cont=0;
    for(int i=1;i<=n;i++)
    {
        int t;
        scanf("%d",&t);
         if(t==c)
             a[t]++;
         else
         {
            min1[t]=min(min1[t],a[t]-a[c]);//前缀区间中的a[t]-a[c]的最小值
            a[t]++;
            cont=max(cont,a[t]-a[c]-min1[t]);//该区间的最值
         }
    }
    cout<<a[c]+cont<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值