蓝桥云客 卡牌
2.卡牌 - 蓝桥云课
卡牌
问题描述
这天,小明在整理他的卡牌。
他一共有n种卡牌,第i种卡牌上印有正整数i(i∈[1,n]),且第i种卡牌现有a_i张。
而如果有n张卡牌,其中每种卡牌各一张,那么这n张卡牌可以被称为一套牌。小明为了凑出可能多套牌,拿出了m张空白牌,他可以在上面写上数i,将其当做第i种牌来凑出套牌。然而小明觉得手写的牌不太美观,决定第i种卡牌最多手写b_i张。
请问小明最多能凑出多少套牌?
输入格式
输入共3行,第一行为两个正整数n, m。
第二行为n个正整数a_1, a_2, ..., a_n。
第三行为n个正整数b_1, b_2, ..., b_n。
输出格式
一行,一个整数表示答案。
样例输入
4 5
1 2 3 4
5 5 5 5
样例输出
3
样例说明
这5张空白牌中,拿2张写1,拿1张写2,这样每种牌的牌数就变为了3, 3, 4,可以凑出3套牌,剩下2张空白牌不能再帮助小明凑出一套。
评测用例规模与约定
- 对于30%的数据,保证n < 2000;
- 对于100%的数据,保证n ≤ 2 × 10^5;a_i, b_i ≤ 2n;m ≤ n^2。
运行限制
- 最大运行时间:1s
- 最大运行内存:512M
总通过次数:3448 | 总提交次数:4060 | 通过率:84.9%
难度:中等 标签:2022 国赛 二分
思路:
贪心思路,能凑出一组排就凑,a数组不够就用b数组和m的,如果凑不出来就结束了。
代码如下:
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll n,a[N],b[N],m;
ll cnt = 0;
int main()
{
cin >> n >> m;
for(ll i = 1 ; i <= n ; i++)
cin >> a[i];
for(ll i = 1 ; i <= n ; i++)
cin >> b[i];
bool found = true;;
while(1)
{
for(ll i = 1 ; i <= n ; i++)
{
if(a[i] > 0)
{
a[i]--;
}
else if(b[i] > 0 && m > 0)
{
b[i]--;
m--;
}
else
{
found = false;
break;
}
}
if(found)
cnt++;
else
break;
}
cout << cnt;
return 0;
}
思路:
二分枚举凑出卡牌的次数,然后跟贪心思维的过程类似,都是要模拟这个枚举的组数是否能成功。
代码如下:
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll n,a[N],b[N],m;
ll sum = 0;
bool check(ll x)
{
ll p = m;
for(ll i = 1 ; i <= n ; i++)
{
if(a[i] >= x)
continue;
else if(a[i] + b[i] < x)//可使用凑数的牌都不够直接return false;
return false;
else if(a[i] + b[i] >= x && p > 0)
{
p = p - ( b[i] - ((a[i] + b[i]) - x));
}
else
return false;
}
return true;
}
int main()
{
cin >> n >> m;
for(ll i = 1 ; i <= n ; i++)
{
cin >> a[i];
sum += a[i];
}
for(ll i = 1 ; i <= n ; i++)
cin >> b[i];
ll l = 0,r = 2*N;
while(l + 1 != r)
{
ll mid = (l + r)/2;
if(check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << l;
return 0;
}