原题链接:
https://codeforces.com/problemset/problem/574/A
Limak is a grizzly bear who desires power and adoration. He wants to win in upcoming elections and rule over the Bearland.
There are n candidates, including Limak. We know how many citizens are going to vote for each candidate. Now i-th candidate would get ai votes. Limak is candidate number 1. To win in elections, he must get strictly more votes than any other candidate.
Victory is more important than everything else so Limak decided to cheat. He will steal votes from his opponents by bribing some citizens. To bribe a citizen, Limak must give him or her one candy - citizens are bears and bears like candies. Limak doesn't have many candies and wonders - how many citizens does he have to bribe?
The first line contains single integer n (2 ≤ n ≤ 100) - number of candidates.
The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 1000) - number of votes for each candidate. Limak is candidate number 1.
Note that after bribing number of votes for some candidate might be zero or might be greater than 1000.
Print the minimum number of citizens Limak must bribe to have strictly more votes than any other
candidate.
5 1 11 2 8
4
In the first sample Limak has 5 votes. One of the ways to achieve victory is to bribe 4 citizens who want to vote for the third candidate. Then numbers of votes would be 9, 1, 7, 2, 8 (Limak would have 9 votes). Alternatively, Limak could steal only 3 votes from the third candidate and 1 vote from the second candidate to get situation 9, 0, 8, 2, 8.
In the second sample Limak will steal 2 votes from each candidate. Situation will be 7, 6, 6, 6.
In the third sample Limak is a winner without bribing any citizen.
题意:有n个人,每个人都有选票,Limak在第一位,Limak想胜出,他可以贿赂其它人让自己的选票加1,别人的选票减1,问至少Limak至少需要贿赂多少人才能让自己的选票比别人的都多。
思路:每次从其余人中选取最多的选票,然后贿赂一票,重新加入序列,当Limak的选票比最多的选票都多的时候退出。(优先队列和最大堆都可以,因为优先队列也是一个堆,可以自己写个最大堆)
AC代码:
优先队列:
#include<iostream>
#include<algorithm>
#include<queue>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
priority_queue<int> q; //优先队列
int main(){
IOS;
int n,x;
cin >> n; //n个人
cin >> x; //第一个为Limak的选票
int nx;
for(int i=0;i<n-1;i++){ //剩下人的选票
cin >> nx;
q.push(nx);
}
int ans=0;
while(!q.empty()){
int temp=q.top(); //每次取最大的选票
q.pop();
if(temp<x) break; //如果最大的选票都小于Limak的,那么就退出
x++,temp--,ans++; //Limak选票数加1,当前最大的选票减1,需要贿赂的人加1
if(temp>0) q.push(temp); //重新推进队列
}
cout << ans << endl;
return 0;
}
最大堆:
#include<iostream>
#include<algorithm>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
int Max_heap[1000]; //最大堆
int node=0; //堆内节点个数
void push(int val){ //插入一个数
Max_heap[++node]=val; //默认插到最后
int Temp_node=node; //从最后开始往前寻找位置
while(Temp_node>1){ //不是根节点说明还有父节点,可以继续找
int root=Temp_node/2; //父节点
if(Max_heap[root]<Max_heap[Temp_node]){ //父节点比子节点小,交换
swap(Max_heap[root],Max_heap[Temp_node]);
Temp_node/=2; //更新位置
}
else break; //否则父节点大于子节点,满足最大堆,退出
}
}
int pop(){ //删除堆顶元素
int top=Max_heap[1]; //保存堆顶元素
Max_heap[1]=Max_heap[node]; //把最后一个点提到堆顶
Max_heap[node]=0; //删除最后一个点
int Temp_node=1; //从跟节点开始找
while(2*Temp_node<node){ //说明有子节点
int L_child=Temp_node*2; //左子节点
int R_child=Temp_node*2+1; //右子节点
if(R_child>=node||Max_heap[L_child]>Max_heap[R_child]){ //没有右子节点(因为这个点已经删除了)或者左子节点更大
if(Max_heap[L_child]>Max_heap[Temp_node]){ //左子节点大于父节点则交换
swap(Max_heap[L_child],Max_heap[Temp_node]);
Temp_node=L_child; //更新位置
}
else break; //否则找到满足的位置,直接退出
}
else{ //右子节点更大时
if(Max_heap[Temp_node]<Max_heap[R_child]){ //右子节点大于父节点
swap(Max_heap[Temp_node],Max_heap[R_child]); //交换
Temp_node=R_child; //更新位置
}
else break; //否则找到满足的位置,退出
}
}
node--; //删除最后的节点
return top; //返回保存的堆顶元素
}
int main(){
IOS;
int n; //n个人
int x;
cin >> n;
cin >> x; //Limak的票数
int nx;
for(int i=1;i<n;i++){ //剩下的人的票数
cin >> nx;
push(nx); //推进堆
}
int ans=0; //需要贿赂的人数
while(node>0){ //堆不为空
int temp=pop(); //出堆
if(temp<x) break; //堆中最大值比Lima看票数少则推出
temp--,x++,ans++; //当前最多票数减1,Limak票数加1,需要贿赂的人加1
if(temp>0) push(temp); //这个票数还大于0则需要推进堆
}
cout << ans << endl;
return 0;
}