题目描述
这天,小明在整理他的卡牌。
他一共有 n 种卡牌,第 i 种卡牌上印有正整数数 i(i ∈ [1, n]),且第 i 种卡牌 现有 ai 张。
而如果有 n 张卡牌,其中每种卡牌各一张,那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌,拿出了 m 张空白牌,他可以在上面写上数 i,将其当做第 i 种牌来凑出套牌。然而小明觉得手写的牌不太美观,决定第 i 种牌最多手写 bi 张。
请问小明最多能凑出多少套牌?
输入格式
输入共 3 行,第一行为两个正整数 n, m。
第二行为 n 个正整数 a1, a2, ..., an。
第三行为 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 张空白牌不能再帮助小明凑出一套。
对于 30% 的数据,保证 n ≤ 2000 ;
对于 100% 的数据,保证 n ≤ 2 × 105 ; ai , bi ≤ 2n; m ≤ n2 。
题解
解法一 遍历循环
此方法不完全可行,只能通过百分之四十的数据,然后就会运行超时
伪代码
1. 将ai排序,取出其中最小的数amin,这个数加到总套数中,ai-amin 2. 对于手写牌 1.找到所有ai==0 2.判断 该ai已经手写牌<=bi && 总手写牌<=m 3.ai==0 加一 3. 返回1
代码
#include<iostream> #include<algorithm> using namespace std; typedef struct { int a; int b; } BR; //a是前面的数 b是后面的数 bool compare(BR br1, BR br2) { return br1.a < br2.a; } BR br1[200500]; int main() { int min_brand; long long int n, m; cin >> n >> m; for (long long int i = 0; i < n; ++i) { cin >> br1[i].a; } for (long long int i = 0; i < n; ++i) { cin >> br1[i].b; } int flag = 0; long long int sum_brand = 0, sum = 0; while (1) { //找到所有数字中最小的数字 sort(br1, br1 + n, compare); //每个数字都减去最小的数字 int t; t = br1[0].a; sum_brand += t; for (int i = 0; i < n; ++i) { br1[i].a -= t; } for (int i = 0; i < n; ++i) { if (br1[i].a == 0) { if (br1[i].b > 0 && sum < m) { br1[i].b -= 1; br1[i].a++; sum++; } else { flag = 1; break; } } } if (flag == 1) { break; } } cout << sum_brand; return 0; }
解法二 二分枚举
伪代码
1. 找到二分查找上下界l r 2. l < r进入循环 2.1 mid = (r+l)/2 2.2 考察每种牌是否符合条件 2.2.1 条件1: A[i]+B[i] < mid 2.2.2 条件2: mid-A[i] >= 手写牌余额 2.3 根据是否符合条件更新r和l
代码
#include<stdio.h> const int N = 2 * 1e5; int A[N], B[N]; int main() { int n; long long m; scanf("%d %lld", &n, &m); for (int i = 0; i < n; ++i) scanf("%d", A + i); for (int i = 0; i < n; ++i) scanf("%d", B + i); int l = 0, r = 3 * n, mid; long long buf = m; while (l < r) { int flag = 1; mid = r + l + 1 >> 1; for (int i = 0; i < n; ++i) { if (A[i] >= mid) continue; if (A[i] + B[i] < mid || mid - A[i] >= buf) { flag = 0; break; } buf -= mid - A[i]; } if (flag) l = mid; else r = mid - 1; } printf("%d", l); return 0; }