问题描述
这天, 小明在整理他的卡牌。
他一共有 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 张空白牌不能再帮助小明凑出一套。
2.解题思路
对暴力的优化
对卡牌按ai从小到大经行排序,找到最后一个与第一张卡牌ai数值相同的卡牌j 同时对0-j的卡牌经行操作
我们可以发现0-j状态很相识,只是bi的数值不一样,所以我们可以不用记录全部的过程,只用第一个卡牌来代表0-j的卡牌。将第一个卡牌的b0赋值为0-j bi的最小值就行了,因为后面经行判断的时候,只需要用到0-j bi的最小值
代码
#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
struct yupiao {
public:
int x;
long long int y;
yupiao(int x, long long int y) {
this->x = x;
this->y = y;
}
};
bool cmp(yupiao a, yupiao b) {
if (a.x == b.x)return a.y < b.y;
return a.x < b.x;
}
void findLast(vector<yupiao> &v, int &index) {//引用传递 要改变值
while (index != v.size() - 1 && v[0].x == v[index + 1].x) {//找到最后一个相同的
if (v[0].y > v[index + 1].y)v[0].y = v[index + 1].y;//将最小的y值赋给v[0].y 用v[0]代替所有相同 x值的邮票
index++;
}
}
void tan(long long int& m, int& count, vector<yupiao>& v) {
if (v.size() == 1) { count = v[0].x + v[0].y; return; }//邮票数为一,直接返回
count += v[0].x;//将最小的x赋值给 count
int index = 0;
findLast(v, index);
while (m > 0) {
if (index != v.size() - 1) {
long long int chazhi = v[index + 1].x - v[index].x;//记录index邮票和index+1邮票的x差值
long long int geshu = m / (index + 1);//记录空白邮票最多能平均分给index+1个邮票的数目
if (geshu < 0)return;//如果空白邮票不够 直接返回
if (v[0].y < chazhi) {//v[0].y可用空白邮票代替的个数 小于差值 也就是之后的v[0].y一定不能满足下一个状态
if (geshu > v[0].y) {
count += v[0].y;
return;
}
else {
count += geshu;
return;
}
}
else {
if (geshu >= chazhi) {
count += chazhi;
m -= (chazhi * (index + 1));
v[0].y -= chazhi;//用v[0]代替所有相同 x值的邮票
v[0].x += chazhi;
findLast(v, index);//进入下一个状态
}
else {
count += geshu;
return;
}
}
}
else {
long long int t = m / (index + 1);
count = count + (t > v[0].y ? v[0].y : t); return;
}
}
}
int main() {
int n, count = 0;
long long int y, m;
cin >> n >> m;
int* v = new int[n];
vector<yupiao>v2;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
for (int i = 0; i < n; i++) {
cin >> y;
v2.push_back(yupiao(v[i], y));
}
sort(v2.begin(), v2.end(), cmp);//对邮票经行排序
tan(m, count, v2);
cout << count;
return 0;
}