[Luogu] P5815 [CQOI2010]扑克牌

Posted andysj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Luogu] P5815 [CQOI2010]扑克牌相关的知识,希望对你有一定的参考价值。

Description

你有(n)种牌,第(i)种牌的数目为(c_i)?。另外有一种特殊的牌(joker),它的数目是(m)。你可以用每种牌各一张来组成一套牌,也可以用一张(joker)和除了某一种牌以外的其他牌各一张组成(1)套牌。比如,当(n=3)时,一共有(4)种合法的套牌:(,,,{1,2,3},{J,2,3},{1,J,3},{1,2,J})

给出(n)(m)(c_i),你的任务是组成尽量多的套牌。每张牌最多只能用在一副套牌里(可以有牌不使用)。

Solution

转化一下题意就很好做了。

现在有(n)竹子(每根竹子有(c_i)节,每节竹子高度为 (1)),可以通过消耗一点法力值使某一根竹子的某两节之间再长出特殊的一节,现在有(m)点法力值,我需要在保证同一高度只能有不超过 (1)节特殊的竹节的情况下,使最矮的那根竹子高度尽可能的高。

所以直接二分答案就好了。

(check)里面就直接算出最短竹子长(x)时,要消耗的法力值(sum)。注意(sum)除了要(le{m}),还要(le{x}),因为同一高度只能有不超过 (1)节特殊的竹节。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int n, m, res, l, r, mn = 2e9, c[55];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < ‘0‘ || ch > ‘9‘) { if (ch == ‘-‘) fl = -1; ch = getchar();}
	while (ch >= ‘0‘ && ch <= ‘9‘) {x = (x << 1) + (x << 3) + ch - ‘0‘; ch = getchar();}
	return x * fl;
}

int check(int x)
{
	ll sum = 0ll;
	for (int i = 1; i <= n; i ++ )
		sum += max((x - c[i]), 0);
	return sum <= min(x, m);
}
 
int main()
{
	n = read(); m = read();
	for (int i = 1; i <= n; i ++ ) c[i] = read(), mn = min(mn, c[i]);
	l = 0; r = 2e9;
	while (l <= r)
	{
		int mid = (l + r) >> 1;
		if (check(mid)) res = mid, l = mid + 1;
		else r = mid - 1;
	}
	printf("%d
", res);
	return 0;
}

以上是关于[Luogu] P5815 [CQOI2010]扑克牌的主要内容,如果未能解决你的问题,请参考以下文章

「luogu4462」[CQOI2018]异或序列

luogu3168 [CQOI2015]任务查询系统

luogu2261 [CQOI2007]余数求和

luogu P3153 [CQOI2009]跳舞

Luogu3163 [CQOI2014]危桥 ---- 网络流 及 一个细节的解释

Luogu2261 [CQOI2007]余数求和