这道题题意很简单:就是一次操作:把最大的-1,最小的+1,问经过k次操作之后最大-最小值是多少,就OK了;
但是怎么写呢?我刚开始想用set来写,不断模拟这个方法,但是一看k是1e9,所以这个想法取消了;
之后我队友写出来了;
他说可以根据k值整体+,-;
然后我想了一下这个东东:
用一个map记录每个 数字出现的次数;
如果脑袋灵活的,应该可以知道这个:如果我k=2;那么对应的map[5]是不是就应该直接都向下-1;并且map[1]是不是直接向上+1;
所以他们不断向中间靠拢;
然后原来的map[5]就应该变为0,map[1]也是;所以可以发现这个可以整体+1或者-1;同时,向下的区间和向上的区间对应个数++;然后判断是不是这个对应的map值为0,如果左边为0那么就l++,如果右边为0就r–;
对于最后结束的条件;可以知道:
比如2 2 2 2 那么k不管是多少次那么max-min==0;然后还有这种5 6那么不管k为多少,差值一直都是1了,所以循环到这两种情况就可以break了;
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,k,a[500050];
unordered_map<int,int> mm;
int main(){
while(~scanf("%d %d",&n,&k)){
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
mm[a[i]]++;
}
sort(a,a+n);//排序
int left=a[0],right=a[n-1];
while(k>0){
int t=min(min(mm[left],mm[right]),k);//取最小的,因为是整体改变
k-=t;//k消耗的次数
mm[left]-=t;//左边变的个数
mm[right]-=t;//右边变的个数
mm[left+1]+=t;//左边整体+1,使得left+1的个数增加t个
mm[right-1]+=t;//右边整体-1,使得right-1的个个数+t个
if(!mm[left])left++;//如果这个给变没有了,那么就指向右边一个数字
if(!mm[right])right--;//如果这个给变没有了,那么就指向左边一个数字
if(right-left==1||right-left==0)break;//这就是最坏的情况下,跳出,因为如果这里结束循环,那么说明后面剩余的k次 不管怎么变也只能是这两个值中的一个
}
cout<<right-left<<endl;//输出答案
mm.clear();//注意清0
}
return 0;
}