1. 程式人生 > >【CodeForces - 349C】Mafia(思維模擬,優秀的二分)

【CodeForces - 349C】Mafia(思維模擬,優秀的二分)

題幹:

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 a

i 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, ..., a

n (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一樣。