CF1328F

看了题,写了一发,发现假了,赶紧退赛

所以咕咕咕

早上起来填坑,发现我的思路并没有假。。。

回到正题,我们发现每次操作的数只能是最大或最小。显然有个结论是最后相等的(k)个数一定是本身存在于(a[i])的数(如果大向小靠近,不会变成更小,反之亦然)。然后,要使一个数变成(a[i]),必须把其他的一堆数全部变成(a[i] - 1)(a[i] + 1)。最后分三种情况讨论一下就好。

PS : 记得离散化。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define N 700005
map <int, int> used;

int n, k, a[N], b[N], cnt[N];

ll sum[N], suf[N];

int main()
{
	scanf("%d%d", &n, &k);
	int tmp = 0;
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]);
		used[a[i]] = 1;
		b[++tmp] = a[i], b[++tmp] = a[i] - 1, b[++tmp] = a[i] + 1;
	}
	sort(b + 1, b + tmp + 1);
	int num = unique(b + 1, b + tmp + 1) - b - 1;
	for(int i = 1; i <= n; i++)
	{
		int x = lower_bound(b + 1, b + num + 1, a[i]) - b;
		cnt[x]++;
		if(cnt[x] >= k) 
		{
			cout << 0 << endl;
			return 0;
		}
	}
	int c = 0;
	for(int i = 1; i <= num; i++)
	{
		if(i > 1) sum[i] = sum[i - 1] + 1ll * c * (b[i - 1] - b[i - 2]);
		c  += cnt[i - 1];
		// cout << b[i] << ' ' << sum[i] << endl;
	}
	c = 0;
	ll ans = LLONG_MAX;
	for(int i = 1; i <= num; i++)
	{
		c += cnt[i];
		if(c < k) continue;
		if(used[b[i]]) ans = min(ans, sum[i] + 1ll * (k - cnt[i]));
	}
	c = 0;
	for(int i = num; i >= 1; i--)
	{
		if(i < num) suf[i] = suf[i + 1] + 1ll * c * (b[i + 2] - b[i + 1]);
		c += cnt[i + 1];
	}
	c = 0;
	// for(int i = 1; i <= num; i++)
	// 	cout << b[i]  << ' ' << sum[i] << ' ' << suf[i] << endl;
	for(int i = num; i >= 1; i--)
	{
		if(used[b[i]]) ans = min(ans, sum[i] + suf[i] + 1ll * (k - cnt[i]));
		c += cnt[i];
		if(c < k) continue;
		if(used[b[i]]) ans = min(ans, suf[i] + 1ll * (k - cnt[i]));
	}
	cout << ans << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/LJB00131/p/12578326.html