Bear and Elections CodeForces - 574A(优先队列和最大堆)

 原题链接:

https://codeforces.com/problemset/problem/574/A

Bear and Elections

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?

Input

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.

Output

Print the minimum number of citizens Limak must bribe to have strictly more votes than any other

candidate.

Examples
input
5
5 1 11 2 8

 
output
4
input
4 1 8 8 8
output
6
input
2 7 6
output
0
Note

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烊@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值