想了一天终于理解了这个题目的思路,
首先我们定义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;
}