题解:B4274 [蓝桥杯青少年组省赛 2023] 数字游戏
题意
操作一:将最大值变成次大值,操作二:将最小值变成次小值。重复执行这两个操作,直到只剩两个不同数字。
思路
一开始我用模拟,TLE 了,30。然后在 dalao 的提示下想到先用结构体存储每个数组出现的次数,然后在一次清空所有最大值与最小值。首先将每个数出现的次数存入
代码
#include <bits/stdc++.h>
using namespace std;
int n, x = 1, y, k, book[1000010];//x为结构体a的起始位置(1),y为结构体的结束位置(长度)
long long ans;
struct node { int num, cnt; } a[1000010];//num存储这个数字,cnt存储这个数字出现的次数
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &k), book[k]++;//数字k的出现次数加1
for (int i = 1; i <= 1000000; i++)
if (book[i])
a[++y].num = i, a[y].cnt = book[i];//将book数组里的数据移到a里,在无形中排好序了
while (y - x + 1 > 2)//如果a的长度(不同数字)大于2就继续
{
k = min(a[x].cnt, a[y].cnt);
a[x].cnt -= k, a[x + 1].cnt += k, ans += k;//一次减去k个数,这里注意最小值减k个,而次小值要加k个,因为最小值变成次小值了
if (!a[x].cnt)//如果最小值被减完了
{
x++;//移到下一位(原来的次小值)
if (y - x + 1 <= 2)//如果a的长度(不同数组)小于等于2
{
printf("%lld %d %d", ans + k - 1, a[x].num, a[y].num);//输出答案,这里ans要加k减1,因为操作一和操作二是交替进行的
return 0;//完美结束
}
}
a[y].cnt -= k, a[y - 1].cnt += k, ans += k;//最大值的数量也减去k个
if (!a[y].cnt)//如果最小值被减完了(原来的次大值)
{
y--;//移到前一位
if (y - x + 1 <= 2)
{
printf("%lld %d %d", ans, a[x].num, a[y].num);//输出答案
return 0;//完美结束
}
}
}
return 0;
}
完结!!!题解来之不易,且看且珍惜。