【CodeForces - 349C】Mafia(思维模拟,优秀的二分)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/83868236

题干:

One day n friends gathered together to play "Mafia". During each round of the game some player must be the supervisor and other n - 1 people take part in the game. For each person we know in how many rounds he wants to be a player, not the supervisor: the i-th person wants to play ai rounds. What is the minimum number of rounds of the "Mafia" game they need to play to let each person play at least as many rounds as they want?

Input

The first line contains integer n (3 ≤ n ≤ 105). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109) — the i-th number in the list is the number of rounds the i-th person wants to play.

Output

In a single line print a single integer — the minimum number of game rounds the friends need to let the i-th person play at least ai rounds.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.

Examples

Input

3
3 2 2

Output

4

Input

4
2 2 2 2

Output

3

Note

You don't need to know the rules of "Mafia" to solve this problem. If you're curious, it's a game Russia got from the Soviet times: http://en.wikipedia.org/wiki/Mafia_(party_game).

题目大意:

     n个人玩游戏,告诉你游戏规则:每轮游戏会有1个裁判,剩下n-1个人当参与者。已知第i个人要求当ai次参与者。。问你至少几轮游戏可以让所有人都心满意足。

解题报告:

   二分轮数。如果满足的话,我们让每个人,除了那ai次当参与者,剩下的都当裁判去,如果此时当的裁判数大于轮数,说明这种轮数就可以,(因为我可以让那些多的人在去当参与者嘛,反正他们不嫌多)然后就可以二分了。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll a[MAX];
int n;
bool ok(ll x) {
	ll sum = 0;
	for(int i = 1; i<=n; i++) sum += (x-a[i]);
	return sum >= x;
	
}
int main()
{
	ll l = 0,r = 1e13;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%lld",a+i),l=max(l,a[i]);
	
	ll mid = (l+r)>>1,ans = 0;
	while(l<=r) {
		mid=(l+r)>>1;
		if(ok(mid)) {
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	printf("%lld\n",ans);
	

	return 0 ;
 }

两个注意事项:

   1.r不能开太大,不能1e13,,因为在ok函数中会越界变成负数就GG了,,所以1e13刚好满足:1e5的n去乘上ok函数中极限状态的x(也就是r的最大取值)要小于longlong的范围、、、所以1e13就很合适、、不能想当然的开个最大1e18!!就炸了!!

   2.l不能从0开始取值,而应该从a[i]的最大值  开始。因为如果要从0开始取值,,ok函数中就需要判断如果有一个a[i]<x了就得return 0;因为这就不满足题意,是不可取的轮数!!所以方便起见就在初始化的时候设置好了。。这个和 修路 的那道题 是完全一样的想法。。要先去掉一部分l,,,不要从0开始取,,不然还得在ok函数中return掉,就很麻烦、。(当然也可以AC)

在此也做个总结,二分答案验证的时候,首先要看你的答案 需要满足题目中哪些信息,,然后再决定ok函数中怎么写来一定可以满足这些条件,,比如这个题,几个要求:首先每个人一定要当ai次参与者,剩余的轮数可以随便(也可以当参与者也可以当裁判)其次我要能够成功举办x轮游戏,说明我至少有x个裁判。满足两者点,我们就可以return 1  了。想想其实也不难,是不。

其实啊这题也可以直接O(1)出结果的。因为你看啊其实每次你都在做相同的工作,每次ok函数中都是减掉了所有的a[i],所以直接在main函数中求一个sum=(a[1]+a[2]+....+a[n])。然后求一个方程nx-sum >= x,求解x的最小值就可以了、、、所以啊没必要二分的、、二分就感觉怪怪的,就跟二分求a+b一样。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/83868236