问题描述
这天, 小明在整理他的卡牌。
他一共有 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; } }