问题描述
这天,小明在整理他的卡牌。他一共有n 种卡牌,第 i 种卡牌上印有正整数数 i (i ∈[1,n]), 且第 i 种卡牌现有 ai 张 。 而如果有 n 张卡牌 ,其中每种卡牌各一张,那么这 n 张卡牌可以被称为一套牌。小明为了凑出尽可能多套牌,拿出了 m 张空白牌,他可以在上面写上数 i ,将其当作第 i 种牌来凑出套牌。然而小明觉得手写的牌不太美观。决定第 i 种牌最多手写 bi 张
请问小明最富哦能凑出多少套牌?
输入格式:
输入共三行,第一行为两个正整数n ,m。
第二行为n 个正整数a1,a2,...,an。
第三行为n 个正整数b1,b2,...,bn。
输出格式
一行,一个整数表示答案
样例输入
cpp
4 5
1 2 3 4
5 5 5 5
样例输出
cpp
3
样例说明
这5张空白牌中,拿2张写1 ,拿一张写2,这样每种牌的牌数就变为了3,3,3,4可以凑出3套牌,剩下的2张空白牌不能再帮助小明凑出一套。
cpp
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 200010;
int a[N], b[N];
int n;
LL m;
bool check(int mid)
{
LL t = m;
//尝试将牌分配
for(int i = 1; i <= n; i ++ )
{
//如果牌的套数比当前拥有的牌数多,需要补充mid-a[i]张牌,如果满足可补充牌数b[i]足够则模拟补充
if(mid > a[i] && b[i] >= mid - a[i])
{
t -= mid - a[i];
}
//如果需要补充,但可补充的牌数不够,也无法完成补充,那自然也凑不出mid套牌
else if (mid > a[i] && b[i] < mid - a[i]) return false;
//空白牌不够用了自然也凑不出来
if(t < 0) return false;
}
return true;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ ) cin >> b[i];
//求b[i]+a[i]的最小值minh
int minh = a[1] + b[1];
for(int i = 2; i <= n; i ++ )
{
int x = a[i] + b[i];
if(x < minh)
minh = x;
}
//我们尝试二分能凑成牌的套数,牌的套数取决于最小一组牌的数量,在没有m限制的情况下,补充后最小牌的数量就是minh,因此区间范围为[0,minh]
int l = 0, r = minh;
while(l < r)
{
int mid = l + r + 1 >> 1;
//满足,表示mid符合条件,由于求最大值,更新左边界为mid
if(check(mid)) l = mid;
//不满足,表示mid太大了,更新右边界
else r = mid - 1;
}
cout << l << endl;
return 0;
}
cpp
//堆排序的方法做复杂度为查找最小牌 o(log n) 和 插入次数 o(n)
// 为 o(log n)*o(n)
//贪心为遍历4次的复杂度 + 排序一次复杂度
// 为 o(n) + o(log n)
//运用贪心算法,将牌从小到大排(保证前面的排小于后面的排)好序之后对前 i 张牌求和加上空白排
//再除以 i (使加上空白排后前i张排都相等)
//如果大于 i 下一个排的初始排量说明有多余的排可以继续由后面的排平摊
//求和要用到前缀和,注意每种牌可添加的上限
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int NUM = 2e5 + 10;
struct A{
int x,y;
bool operator < (const A &c) const{
return x < c.x;
}
};
A a[NUM];
int store[NUM];
int minn = 1e18;
signed main(){
int n,m;
cin>>n>>m;
a[0].x = a[0].y = 0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i].x);
for(int i=1;i<=n;i++) scanf("%lld",&a[i].y);
sort(a+1,a+n+1);
//for(int i=1;i<=n;i++) cout<<a[i].x<<" "; cout<<endl;
for(int i=1;i<=n;i++) store[i] = store[i-1] + a[i].x;
//for(int i=1;i<=n;i++) cout<<store[i]<<" "; cout<<endl;
for(int i=1;i<=n;i++){
minn = min(a[i].y + a[i].x,minn);
int ans = (store[i] + m) / i;
if(i < n) if(ans > a[i+1].x) continue;
if(ans <= minn) cout<<ans;
else cout<<minn;
break;
}
return 0;
}