每日一题-蓝桥杯(卡牌)

该问题是一个关于卡牌组合的问题,小明试图用现有的卡牌和空白牌凑出尽可能多的完整套牌。给定每种卡牌的数量和可手写的最大张数,需要找出最大套牌数。通过二分搜索方法,检查在每个中间值下是否能凑出完整的套牌,从而找到最大值。

卡牌

问题描述

这天, 小明在整理他的卡牌。

他一共有nnn种卡牌,第i种卡牌上印有正整数数i(i∈[1,n]),i(i∈[1, n]),i(i[1,n]),且第i种卡牌现有aaa张。

而如果有nnn张卡牌,其中每种卡牌各一张,那么这nnn张卡牌可以被称为一套牌。小明为了凑出尽可能多套牌,拿出了mmm张空白牌,他可以在上面写上数i,i,i,将其当做第i种牌来凑出套牌。然而小明觉得手写的牌不太美观,决定第iii种牌最多手写bbb张。

请问小明最多能凑出多少套牌?

输入格式

输入共3行,第一行为两个正整数n,m。n, m。n,m
第二行为nnn个正整数a1,a2,...,an。a_1, a_2,.. . ,a_n 。a1,a2,...,an
第三行为nnn个正整数b1,b2,...,bn。b_1, b_2,. . . , b_n 。b1,b2,...,bn

输出格式

一行,一个整数表示答案。

样例输入

4 5
1 2 3 4
5 5 5 5

样例输出

3

样例说明

这 5 张空白牌中, 拿 2 张写 1 , 拿 1 张写 2 , 这样每种牌的牌数就变为了 3,3,3,4 可以凑出 3 套牌, 剩下 2 张空白牌不能再帮助小明凑出一套。

评测用例规模与约定

对于303030%的数据,保证n≤2000;n ≤2000;n2000;
对于100100100%的数据,保证n≤2×105;ai,bi≤2n;m≤n2。n≤2 × 10^5; a_i,b_i≤ 2n; m ≤n^2。n2×105;ai,bi2n;mn2

运行限制

最大运行时间:1s
最大运行内存:512M


思路分析:

根据题意分析我们可以得出当前题目是让我们求出最大值。
由数据范围为 2×1052×10^52×105可知,暴力是不可行的,暴力n2n^2n2,直接会超时。
求最大值,我们可以想到使用二分来做,二分时间复杂度O(log2N)O(log_2N)O(log2N),不会超时。

二分:
  1. mid = 当前最多的套牌数量。
  2. check函数
    根据题意我们可以发现
    mid - 当前牌的数量 = 当前牌需要手写的卡牌数 = 当前牌需要的空白牌数
    ①枚举每张牌,如果当前牌的数量大于 midmidmid,那么就跳过这张牌。
    ②如果 midmidmid −- 当前牌的数量 >>> 当前牌可以手写的卡牌数,那么可以发现mid 一定大了,我们就把 r=mid−1。r = mid - 1。r=mid1
    ③如果当前空白牌的数量 <<< midmidmid −- 当前牌的数量,那么可以发现mid还是大了,我们就把 r=mid−1。r = mid - 1。r=mid1
    ④否则就把 l=midl = midl=mid 直到 l=rl = rl=r
代码:
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 2e5 + 10;

typedef long long LL;

LL n, m;
struct c
{
  LL a, b;
} p[N];

bool check(int mid)
{
  LL ans = m; // 空白牌
  for (int i = 1; i <= n; i ++ )
  {
    if(p[i].a > mid) continue; // 如果当前卡牌的张数 > 目前的最多卡牌数,就不用考虑。
    if(mid - p[i].a > p[i].b) return 0; 
    // 目前最多的卡牌数 - 当前卡牌的张数 = 达到目前最多卡牌数所需要的手写牌的数量。
    // 如果当前卡牌所能手写的牌数 < 达到目前最多卡牌数所需要的手写牌的数量,那么就可以得出:目前最多卡牌数大了。
    ans -= mid - p[i].a; // 如果空白牌 < 达到目前最多卡牌数所需要的手写牌的数量,那么就可以得出:空白牌数量少了,目前最多卡牌数大了。
    if(ans < 0) return 0;
  }
  return 1;
}

int main()
{
  // 请在此输入您的代码
  cin >> n >> m;
  for (int i = 1; i <= n; i ++ ) cin >> p[i].a;
  for (int i = 1; i <= n; i ++ ) cin >> p[i].b;
  
  int l = 0, r = 2 * n;
  while (l < r)
  {
    int mid = l + r + 1 >> 1;
    if(check(mid)) l = mid;
    else r = mid - 1;
  }
  cout << r << endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值