[CQOI2010]扑克牌
[CQOI2010]扑克牌
https://ac.nowcoder.com/acm/problem/19916
二分
题意:
你有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,你的任务是组成尽量多的套牌。每张牌最多只能用在一副套牌里(可以有牌不使用)。
我不知道贪心行不行,如果有大佬知道怎么贪心,希望指点一下。
下面是二分做法:
我们想对结果进行二分,我们可以组成的套数一定是在[0,1e9) 左闭右开,我们在这个范围内进行二分搜索。
对于左端点l,右端点r,中间点mid,
如果中间点为true,即我们可以凑出mid及mid以上的套装数,那么我们让l = mid+1
否则我们让 r = mid-1
这样最后答案一定为l-1
关键是如何判断我们是否可以凑出mid或mid以上的套装数
我们想想,如果我们要凑出mid套卡组,对于卡牌a[i],a[i]<mid。
那么我们肯定要用joker代替他!如果最后我们,需要使用的joker数大于我们实际拥有的joker数
那么我们肯定不能成功凑出mid套卡组。
除此之外还有什么限定条件呢?对了,对于一套卡组我们最多只能用joker替代其中的一张,及我们
不能出现[j,j,3]的情况。那么这个限制条件如何体现呢?
我们想象假设mid = 6;a[i]=4,那么我们要使用2张joker代替他 a[j] = 3我们使用三张joker代替他。
我们这样代替吗?1代表一张卡牌
ai [ j, j, 1, 1, 1, 1]
aj [ j, j, j, 1, 1, 1]
不会的,因为这样当我们从上方去拿第一套卡组时,就有大于一张的joker了
所以我们这样放
ai [ j, j, 1, 1, 1, 1]
aj [ 1, 1, j, j, j, 1]
有没有看出什么,我们只能接着上一次的末尾放置joker
最多放置mid张joker
所以倘若我们放置的joker数大于mid的话,也依然是false
代码如下,注意细节
#include<iostream>; #include<algorithm>; using namespace std; typedef long long ll; const int max_r = 1e9 + 10; const int max_n = 55; int a[max_n]; int n, k; int solve() { int l = 0;int r = max_r; while (l <= r) { int mid = (r + l) >> 1; ll cnt = 0; for (int i = 1;i <= n;i++) if (a[i] < mid) cnt += mid - a[i]; if (cnt > mid || cnt > k) r = mid - 1; else l = mid + 1; }return l - 1; } int main() { ios::sync_with_stdio(0); cin >> n >> k; for (int i = 1;i <= n;i++)cin >> a[i]; cout << solve() << endl; }