1. 程式人生 > >CF1082E Increasing Frequency (multiset+亂搞+貪心)

CF1082E Increasing Frequency (multiset+亂搞+貪心)

題目連結

題目大意:
n a i ,

m
[ l , r ] ,
m 給你n個數a_i,給定一個m,你可以選擇一個區間[l,r],讓他們區間加一個任意數,然後詢問一次操作完之後,最多能得到多少個m

QWQ

考場上真的**

想了好久都不會,直到考試快結束才知道怎麼做。

首先,根據題目,我們可以得知,假設我們修改了 [ l , r ] [l,r] 這個區間,那麼最後的 a n s ans 就應該是總的m的個數,減去區間中m的個數,加上區間內的眾數的個數

QWQ

那麼我們考慮怎麼來處理這個。
首先,每個數字之間都是獨立的。
所以我們可以預處理每一個數字出現的位置。

然後假設當前我們要計算的數字是 x x

那麼,我們可以先對於所有出現的位置 i i ,求一個 [ p o s 1 , p o s i ] [pos_1,pos_i] 的答案QWQ

轉移的式子也是比較顯然。

d p [ i ] = d i [ i 1 ] + 1 ( s u m m ) dp[i]=di[i-1]+1-(sum_m)
其中 s u m m sum_m 表示這段區間中的m的個數,這個可以用字首和來維護

dp[j]=dp[j-1]+1-(sum[v[i][j]]-sum[v[i][j-1]]);

那麼既然求出來這個東西,我們考慮左端點每移動一個,相當於對所有的右端點的區間加一個釋放出來的貢獻,也就是m的個數-1

所以說,我們現在需要一個能支援插入,刪除,字尾修改, m a x 求max 的一個數據結構

很自然能想到 m u l t i s e t multiset ,插入刪除和max就不說了,字尾修改的話,我們只需要維護一個 d e l t a delta 表示改變數,對於每個元素,呼叫的時候都 + d e l t a +delta 就解決了

QWQ

給程式碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 5e5+1e2;
int n,a[maxn];
int m;
int sum[maxn];
vector<int> v[maxn];
int cnt;
int vis[maxn];
int dp[maxn];
int ans;
int main()
{
  n=read(),m=read();
  for (int i=1;i<=n;i++) v[i].push_back(0);
  for (int i=1;i<=n;i++) 
  {
    a[i]=read();
    if (!vis[a[i]])
    {
     ++cnt;
        vis[a[i]]=cnt;
 }
 v[vis[a[i]]].push_back(i);
  }
  for (int i=1;i<=n;i++) if(a[i]==m) sum[i]=1;
  for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
  ans=sum[n];
  for (int i=1;i<=cnt;i++)
  {
   if (a[v[i][1]]==m) continue;
   int num = v[i].size();
   multiset<int> s;
   dp[1]=1;
   s.insert(1);
   for (int j=2;j<num;j++)
   {
    dp[j]=dp[j-1]+1-(sum[v[i][j]]-sum[v[i][j-1]]);
    //cout<<j<<" "<<dp[j]<<endl;
    s.insert(dp[j]);
 }
 ans=max(ans,(*(s.rbegin()))+sum[n]);
 int j=1;
 int delta=0;
 while (j<num-1)
 {
  s.erase(s.find(dp[j]));
  j++;
  delta+=sum[v[i][j]]-sum[v[i][j-1]]-1;
  ans=max(ans,(*(s.rbegin()))+delta+sum[n]);
 }
  } 
  cout<<ans;
  return 0;
}