『题解』CF1490F Equalize the Array
题意
二次元来了!快跑!
一天,雷姆姐姐在修剪花园。罗兹沃尔的花园非常豪华,而且都是由雷姆姐姐一手操办。傲娇~(不是
但是罗兹沃尔的强迫症又犯了,他不希望自己花园非常的凌乱,他希望自己花园中不同种类的花数目相同,所以安排雷姆姐姐帮他处理花园中的花。
然鹅雷姆姐姐每天都要和你玩耍努力工作,非常劳累,热心肠的你决定帮助她。
你可以帮雷姆把多余的花剪走,使得最后花园中不同种类的花数目相同。
问达成目的最少的操作数。
话说这样的题面你们不喜欢么。。。那还不赶紧点赞
解析
显然是要寻找一条界限,使得界限以上的不同元素出现次数相等,界限一下的元素删至数目为零,直接枚举寻找这条界线就好了。
可以考虑对元素数据进行离散化,然后桶排序,将各个元素出现的次数记录到几个 \(bkt[i] \ ( bucket )\) 里,然后可以进行两种操作:
-
判断在界限以上的元素数目删除到界限值
-
判断在界限一下的元素数目直接清除,也就是删除到 \(0\) 。
然而直接挨个删除元素会超时,考虑如何进行优化。
不都已经把各种元素出现次数统计下来了吗,事先处理前缀和不就好了嘛~
所以删除次数显然易见:
-
界限以上的元素所需的删除次数就是前缀和
-
界限一下的元素删除次数是用前缀和减去这些元素的个数 \(\times\) 界限值
你们最爱的环节
/*
Name: CF1490F Equalize the Array
By Frather_
*/
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define InF 0x3f3f3f3f
using namespace std;
/*=========================================快读*/
int read() //快读不解释
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
/*=====================================定义变量*/
int T;
int n;
int a[300030], a_[300030];
int n_; //记录界限值
int bkt[300030];
int sum[300030]; //记录前缀和
int ans[300030], ans_[300030];
int res = InF; //最终结果
/*====================== =============自定义函数*/
void prepare() //多组数据,清空变量
{
n = 0;
memset(ans, 0x3f, sizeof(ans));
memset(ans_, 0x3f, sizeof(ans_));
n_ = 0;
memset(bkt, 0, sizeof(bkt));
memset(sum, 0, sizeof(sum));
res = InF;
}
/*=======================================主函数*/
int main()
{
T = read();
while (T--)
{
prepare();
n = read();
for (int i = 1; i <= n; i++) //读入数据,动态复制一组数据,利于下面的离散化
{
a[i] = read();
a_[i] = a[i];
}
sort(a_ + 1, a_ + n + 1);
n_ = unique(a_ + 1, a_ + n + 1) - a_ - 1;
for (int i = 1; i <= n; i++) //离散化没什么解释的
a[i] = lower_bound(a_ + 1, a_ + n_ + 1, a[i]) - a_;
for (int i = 1; i <= n; i++) //桶排序记录元素出现次数
bkt[a[i]]++;
sort(bkt + 1, bkt + n_ + 1);
for (int i = 1; i <= n_; i++)
sum[i] = sum[i - 1] + bkt[i];
for (int i = 1; i <= n; i++)
{
int t = lower_bound(bkt + 1, bkt + n_ + 1, i) - bkt;
if (t > n_) //界限以上
ans[i] = sum[n_];
if (t < n_) //界限一下
ans_[i] = sum[t - 1] + sum[n_] - sum[t - 1] - (n_ - t + 1) * i;
}
for (int i = 1; i <= n; i++) //统计答案
res = min(res, min(ans[i], ans_[i]));
printf("%d\n", res);
}
return 0;
}
友情提示
\[多组数据一定要记得清空变量!!!
\]
\[多组数据一定要记得清空变量!!!
\]
\[多组数据一定要记得清空变量!!!
\]
别问我为什么这么说。。。有苦有泪我不说