CF1328F 题解

CF1328F 题解

$\text{Descrption}$

给定 $n$ 个数,每次可以将最小的数加一或者将最大的数减一,问要有 $k$ 个相等的数最少需要多少此操作。

$n,k\le 2\times 10^5,a_i\le 10^9$。

$\text{Solution}$

首先容易发现排序不影响答案。

然后考虑把序列分为若干个段,每段内数都相同,不同的段内数不相同。

我们想要枚举最后 $k$ 个相同的数的数值,但是直接枚举复杂度太高。我们发现,若这个数值在序列中不存在,它一定不是最优的。所以我们直接枚举每个段计算答案即可。

$\text{Code}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
#define REG register
using namespace std;

typedef long long ll;
const int Maxn=200005;

inline void read(int& x){
static char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

int n,k;

int a[Maxn];

ll pre[Maxn],suf[Maxn];
int l[Maxn],r[Maxn],tot;

inline void Work(){
read(n),read(k);
for(REG int i=1;i<=n;++i) read(a[i]);
sort(a+1,a+n+1);
for(REG int i=1;i<=n;++i) pre[i]=pre[i-1]+a[i];
for(REG int i=n;i;--i) suf[i]=suf[i+1]+a[i];
for(REG int i=1;i<=n;++i)
if(a[i]==a[i-1]) ++r[tot];
else ++tot,l[tot]=r[tot]=i;
ll ans=50000000000000000ll;
for(REG int i=1;i<=tot;++i){
int len=r[i]-l[i]+1;
if(len>=k) {puts("0");return;}
if(r[i]>=k) ans=min(ans,1ll*(l[i]-1)*(a[l[i]]-1)-pre[l[i]-1]+k-len);
if(n-l[i]+1>=k) ans=min(ans,suf[r[i]+1]-1ll*(n-r[i])*(a[l[i]]+1)+k-len);
if(r[i]<k&&n-l[i]+1<k) ans=min(ans,1ll*(a[l[i]]-1)*(l[i]-1)+suf[r[i]+1]-1ll*(a[l[i]]+1)*(n-r[i])-pre[l[i]-1]+k-len);
}
printf("%lld\n",ans);
getchar(),getchar();
}

int main(){Work();}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×