Educational Codeforces Round 55 (Rated for Div. 2) E - Increasing Frequency(枚举+尺取)

题意

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

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/84669497