【BZOJ1816】[Cqoi2010]扑克牌 二分

【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;
}
时间: 2024-10-12 05:50:33

【BZOJ1816】[Cqoi2010]扑克牌 二分的相关文章

bzoj1816: [Cqoi2010]扑克牌(二分答案判断)

1816: [Cqoi2010]扑克牌 题目:传送门 题解: 被一道毒瘤题搞残了...弃了坑来刷刷水题 一开始还想复杂了...结果发现二分水过: 二分答案...然后check一下,joker肯定尽量用mid次,那么哪种牌不够就补(因为每次只能补一种,所以如果次数用完就return false) 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5

BZOJ 1816: [Cqoi2010]扑克牌( 二分答案 )

二分答案.. 一开始二分的初始右边界太小了然后WA,最后一气之下把它改成了INF... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i , n ) for( int i = 0 ; i

bzoj1816: [Cqoi2010]扑克牌

二分答案. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) const int inf=0x7f7f7f7f; int c[55],n,m; bool check(int x){ int cnt=min(x,m); rep(i,n) i

[BZOJ 1816][Cqoi2010]扑克牌(二分答案)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1816 分析: 我先以为是道水题,但是要注意的是每套牌中Joker只能用1张的,所以就出现了可能目前每种牌的剩余牌数都够,但不一定不用Joker,然后就短路了…… 看了hzwer的blog顿时茅塞顿开,原来是二分…… 二分答案x,然后判定 判定的方法:注意每套牌顶多只有一个Joker,所以对于答案x,能用的Joker的最大数量是T=Min(x,m),然后枚举每种牌,将每种牌相对于答案x差的个数

[BZOJ 1816] [Cqoi2010] 扑克牌 【二分答案】

题目链接:BZOJ - 1816 题目分析 答案具有可以二分的性质,所以可以二分答案. 验证一个答案 x 是否可行,就累加一下各种牌相对于 x 还缺少的量,如果总和超过了 x 或 m ,就不可行. 因为,当使用的joker小于等于 x 时,才可以通过合适地安排顺序使得每组牌中至多有一张 joker . 代码 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio>

bzoj 1816: [Cqoi2010]扑克牌

1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 int l,r,m,n,a[60],ans; 5 bool pan(int x) 6 { 7 int a1=min(x,m); 8 for(int i=1;i<=n;i++) 9 if(a[i]<x) 10 { 11 a1-=x-a[i]; 12 if(a1<0) 13 return 0; 14 } 15 return 1; 16 }

BZOJ 1816 扑克牌(二分)

由于答案具有单调性,考虑二分答案并验证. 如果能凑齐x堆,因为每个joke在一个牌堆里最多只能用一次,则至多只能用min(x,m)个joke. 对于每个牌,如果这个牌的总数小于x,用joke补齐剩下的,如果能补齐那么一定能组成x堆. 简单证明: 补齐完后的牌堆里每用joke一个,一定能在其他牌里面凑齐n-1个不是joke的牌. 考虑反证法,如果取某一个joke后,剩下的牌组有一个只剩下joke的话.这是不可能的,因为joke总数至多为x. # include <cstdio> # includ

二分答案 扑克牌

1 program hehe; 2 var 3 n,m,i,j:longint; 4 c:array[0..50] of longint; 5 6 function min(a,b:longint):longint; 7 begin 8 if a>b then exit(b); 9 exit(a); 10 end; 11 12 function ok(a:longint):boolean; 13 var 14 f,t:longint; 15 begin 16 t:=min(a,m); 17 fo

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734