第十三届蓝桥杯C++B组国赛C题——卡牌 (AC)对暴力的优化

问题描述
这天, 小明在整理他的卡牌。

他一共有 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;
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值