蓝桥杯真题——卡牌_二分_快读

问题描述

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

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

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

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

输入格式

输入共 3 行, 第一行为两个正整数 ,n,m 。

第二行为 n 个正整数 1,2,…,a1​,a2​,…,an​ 。

第三行为 m 个正整数 1,2,…b1​,b2​,…,bn​ 。

输出格式

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

样例输入

4 5
1 2 3 4
5 5 5 5

样例输出

3

样例说明

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

评测用例规模与约定

对于 30%30% 的数据, 保证 �≤2000n≤2000;

对于 100%100% 的数据, 保证 �≤2×105;��,��≤2�;�≤�2n≤2×105;ai​,bi​≤2n;m≤n2 。

运行限制

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

题目分析

这道题目非常综合,考察了二分以及Java的IO流输入输出

(1)这道题目是通过二分的手段来找到最多的能凑到的牌的套数

一套二分模板(经供参考):

while (left <= right) {
            int mid = left + (right - left) / 2;
            if (check(mid)) {
                res = mid;
                left = mid + 1;
            } else right = mid - 1;
        }

二分的难点有两个:

二分边界,即L和R的退出条件
check函数的函数体实现

(2)这道题目充分的体现了Java的不足,普通的Scanner输入只能拿到30%的分数,这道题目要想拿满分必须要使用Java的I/O流输入

IO流模板:

  static PrintWriter out =new PrintWriter(System.out);
    static BufferedReader ins=new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer in=new StreamTokenizer(ins);
    /**
     * 输入
     * in.nextToken()
     * int a= (int)in.nval;
     *
     * 输出
     * out.print();
     * out.flush();
     */

(3)在做这道题目的时候,我发现Scanner和BufferReader不能同时使用,会出现输入异常,这个点希望大家在做题的时候注意一下!!
(4)还要注意 m的类型要用long 不然会出现段错误 只能拿40%的分

         m = Long.parseLong(split[1]);

参考原文链接:https://blog.csdn.net/m0_55858611/article/details/129544166

 题目代码

import java.io.*;
import java.util.Scanner;

public class 卡牌 {
    static PrintWriter out = new PrintWriter(System.out);
    static BufferedReader ins = new BufferedReader(new InputStreamReader(System.in));
    StreamTokenizer in = new StreamTokenizer(ins);
    static int[]a;
    static int[]b;
    static int n;
    static long m;

    public static void main(String[] args) throws IOException {
        String s = ins.readLine();
        String[] split = s.split(" ");
        n = Integer.parseInt(split[0]);
        m = Long.parseLong(split[1]);
        a = new int[n];
        b = new int[n];
        String[] stringsA = ins.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(stringsA[i]);
        }
        String[] stringsB = ins.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            b[i] = Integer.parseInt(stringsB[i]);
        }
        int left = 0;
        int right = n;
        int res = 0;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (check(mid)) {
                res = mid;
                left = mid + 1;
            } else right = mid - 1;
        }
        out.println(res);
        out.flush();
    }

    static Boolean check(int k) {
        long temp = m;
        for (int i = 0; i < n; i++) {
            if (a[i] > k) continue;
            if (a[i] + b[i] < k) return false;
            if (a[i] + temp < k) return false;
            if (temp >= k - a[i]) {
                temp = temp - (k - a[i]);
            } else return false;
        }
        return true;
    }

}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DaoJis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值