1. 程式人生 > >【BZOJ1816】[Cqoi2010]撲克牌 二分

【BZOJ1816】[Cqoi2010]撲克牌 二分

desc har 其余 特殊 二分 names soft sam led

【BZOJ1816】[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。

題解:二分,然後亂搞~

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n;
int c[60];
int solve(int x)
{
	int i,sum=0;
	for(i=1;i<=n;i++)
	{
		if(c[i]<x)	sum+=x-c[i];
		if(sum>x||sum>c[0])	return 0;
	}
	return 1;
}
int main()
{
	scanf("%d%d",&n,&c[0]);
	int i,l=1<<30,r=0,mid;
	for(i=1;i<=n;i++)	scanf("%d",&c[i]),l=min(l,c[i]);
	r=c[0]+l+1;
	while(l<r)
	{
		mid=l+r>>1;
		if(solve(mid))	l=mid+1;
		else	r=mid;
	}
	printf("%d",l-1);
	return 0;
}

【BZOJ1816】[Cqoi2010]撲克牌 二分