1. 程式人生 > >BZOJ 1816: [Cqoi2010]撲克牌 二分

BZOJ 1816: [Cqoi2010]撲克牌 二分

Description

你有n種牌,第i種牌的數目為ci。另外有一種特殊的牌:joker,它的數目是m。你可以用每種牌各一張來組成一套牌,也可以用一張joker和除了某一種牌以外的其他牌各一張組成1套牌。比如,當n=3時,一共有4種合法的套牌:{1,2,3}, {J,2,3}, {1,J,3}, {1,2,J}。 給出n, m和ci,你的任務是組成儘量多的套牌。每張牌最多隻能用在一副套牌裡(可以有牌不使用)。
Input
第一行包含兩個整數n, m,即牌的種數和joker的個數。第二行包含n個整數ci,即每種牌的張數。

Output

輸出僅一個整數,即最多組成的套牌數目。

Sample Input

3 4

1 2 3

Sample Output

3

樣例解釋

輸入資料表明:一共有1個1,2個2,3個3,4個joker。最多可以組成三副套牌:{1,J,3}, {J,2,3}, {J,2,3},joker還剩一個,其餘牌全部用完。

資料範圍

50%的資料滿足:2 < = n < = 5, 0 < = m < = 10^ 6, 0< = ci < = 200

100%的資料滿足:2 < = n < = 50, 0 < = m, ci < = 500,000,000。

思路

這個題是二分答案。
然後判斷。我們二分出來的答案,看看滿不滿足條件。
看每堆的牌數還要加幾個 joker 牌才能到 我們二分的答案。
最後還要判斷是不是會出現有兩堆出現 joker。

#include<bits/stdc++.h>
using namespace std;
int a[100],n,m;
bool judge(int x){
	int t = min(x,m);
	for (int i = 0; i < n; i++){
		if (a[i] < x) t -= (x - a[i]);
		if (t < 0) return 0;
	}
	return 1;
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i = 0; i < n; i++)
		scanf("%d",&
a[i]); int l = 0,r = 1e9,ans; while(l <= r){ int mid = (l + r) >> 1; if (judge(mid)) { l = mid + 1; ans = mid; } else r = mid - 1; } printf("%d\n",ans); return 0; }