题意
n个数,一个c值,
允许改一次区间[l,r],即把这个区间内的数同时加上或减去一个k,
问修改之后,最多有多少个c值。
思路来源
翼神%%%
题解
枚举哪个值是最后是替代c的值
c显然不需要替代自己,预处理一下[0,n-1]区间有几个c
对每个值跑一遍尺取
如果收益(即获得的值-浪费的值)为负就舍弃
用出现位置建链表next强降复杂度
最后是元素均摊的O(n)复杂度
心得
虽然被讲懂了思路但感觉距AC还差好远
这题考到了之前用过的好多小技巧
(离散化+枚举+链表next+尺取)
但是还是根据输出结果强行debug样例对拍1h
然后RE一发WA一发
对着WA样例才找出来自己的代码不规范之处(color数组没赋-1)
GG 还是基本功不扎实啊 一题补1.5h系列
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=5e5+10;
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<int,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,c,a[maxn],color[maxn],cnt;//染色 离散化
int num[maxn];//统计c在[0,r]中出现过多少次
bool vis[maxn];//该数是否出现过
vector<pii>pos[maxn];//(出现位置,上一个出现位置)的数组
int ans;
int main()
{
mem(color,-1);//避免和0冲突 被样例卡了 还是不规范
sci(n),sci(c);
rep(i,0,n-1)
{
sci(a[i]);
if(!i)num[i]=0;
else num[i]=num[i-1];
if(a[i]==c)num[i]++;
if(!vis[a[i]])
{
color[a[i]]=cnt++;
vis[a[i]]=1;
}
pos[color[a[i]]].push_back(pii(i,-1));
}
rep(i,0,cnt-1)
{
int len=pos[i].size();
rep(j,1,len-1)
{
int pre=pos[i][j-1].first;
pos[i][j].second=pre;//指向上一个节点
}
}
/*
rep(i,0,cnt-1)
{
int len=pos[i].size();
rep(j,0,len-1)
{
printf("::%d (%d,%d)\n",i,pos[i][j].first,pos[i][j].second);
}
}
*/
/*
sum[r]+=(num[x][i]-num[c][i]);//num[x][i],1-i x的个数
sum[l]=min(sum[l],sum[l]+num[x][i]-num[c][i]);
ans=max(ans,sum[r]-sum[l]);
*/
ans=num[n-1];
rep(i,0,cnt-1)//枚举最后[l,r]是哪种元素最多
{
if(color[c]==i)continue;//c的情况特判
int len=pos[i].size(),sum=1,tmp=1;//x出现1次 c被浪费0次 tmp最少可以改一个
rep(j,1,len-1)//数i出现过j+1次
{
int now=pos[i][j].first;
int last=pos[i][j].second;
int waste=(now-1<last)?0:num[now-1]-num[last];//[last+1,now-1]的浪费c的个数
//printf("%d %d %d %d\n",j,now,last,waste);//最大子区间和
sum-=waste;//1 浪费3 1 浪费5 1
if(sum<0)sum=0;
sum++;
tmp=max(sum,tmp);
}
ans=max(ans,tmp+num[n-1]);//[0,l-1]+[r+1,n-1] [l,r]的waste已经减去了
}
printf("%d\n",ans);
return 0;
}