1. 程式人生 > >Educational Codeforces Round 55 (Rated for Div. 2) E - Increasing Frequency(列舉+尺取)

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