Educational Codeforces Round 55 (Rated for Div. 2) E - Increasing Frequency(列舉+尺取)
阿新 • • 發佈:2018-12-03
題意
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; }