蓝桥杯C++大学B组一个月冲刺记录2024/3/7

蓝桥杯C++大学B组一个月冲刺记录2024/3/7

规则:每天三题

1.鱼塘钓鱼

有 N
个鱼塘排成一排,每个鱼塘中有一定数量的鱼,例如:N=5
时,如下表:
鱼塘编号 1 2 3 4 5
第1分钟能钓到的鱼的数量(1…1000) 10 14 20 16 9
每钓鱼1分钟钓鱼数的减少量(1…100) 2 4 6 5 3
当前鱼塘到下一个相邻鱼塘需要的时间(单位:分钟) 3 5 4 4
即:在第 1个鱼塘中钓鱼第 1分钟内可钓到 10条鱼,第 2分钟内只能钓到 8 条鱼,……,第 5
分钟以后再也钓不到鱼了。
从第 1个鱼塘到第 2个鱼塘需要 3分钟,从第 2个鱼塘到第 3个鱼塘需要 5分钟,……
给出一个截止时间 T,设计一个钓鱼方案,从第 1个鱼塘出发,希望能钓到最多的鱼。
假设能钓到鱼的数量仅和已钓鱼的次数有关,且每次钓鱼的时间都是整数分钟。

多路归并
这样思考:当仅考虑前n个池塘的话,可以用总时间减去到达第n个池塘用的时间。剩下的时间K,就是将前n个池塘能获得的鱼的数量降序排列,然后取前K项和,就是答案

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int M = 105;

int a[M],b[M],st[M],spend[M];




int cmp(int i){
    
    return max(0 , a[i] - spend[i] * b[i]);

}

int handle(int n,int T){
    
    memset(spend,0,sizeof(spend));
    
    int ans = 0,t = 1;

    for(int i = 1;i <= T; ++i){
        
        for(int j = 1;j <= n; ++j){
            if(cmp(j) > cmp(t)) t = j;
        }
        ans += cmp(t);
        spend[t] ++;   
        
    }

    return ans;
}


int main(){
    int n,T;
    
    cin >> n;
    
    for(int i = 1;i <= n; ++i) cin >> a[i];
    for(int i = 1;i <= n; ++i) cin >> b[i];
    for(int i = 2;i <= n; ++i){
        cin >> st[i];
        st[i] += st[i-1];
    }
    
    cin >> T;

    int ans = 0;
    for(int i = 1;i <= n;++i){
        ans = max(ans,handle(i,T - st[i]));
    }


    cout << ans << endl;

    return 0;
}

2.谦虚数字

给定一个包含 K个不同质数的集合 S={p1,p2,…,pK}。如果一个数的质因子全部属于集合 S,那么我们就称这个数为谦虚数字。
例如,p1、p1p2、p1p1、p1p2p3…这些数字都是谦虚数字。现在给定整数 K
和集合 S,请你求出从小到大第 N个谦虚数字是多少。
注意,我们规定 1不是谦虚数字。

丑数规律 + 多路归并
一直没找到规律,按照一般多路归并的思路还是看不出规律。
然后有帖子说和丑数那个题一样,就去看了,然后按照丑数的规律就好做了

(由于当n == 1的情况,最小堆的初始化需要特判,第一次交被卡了两组数组,直接在主函数特判了,属于偷懒行为,不可取)

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>

using namespace std;

const int M = 1e5+10;

typedef pair<int,int> PII;

int a[M],res[M],p[M];

int n,T;

void merge(int k){
    int cnt = 0;
    res[0] = 1;  
    for(int i = 1;i <= n;++i){
        p[a[i]] = 0;
    }

    priority_queue<PII,vector<PII>,greater<PII>>q;

    for(int i = 1;i <= n;++i){
        q.push({res[p[a[i]]] * a[i],a[i]});
    }
  
    while(cnt <= k){
        auto t = q.top();
        q.pop();      
        q.push({res[p[t.second]] * t.second , t.second});
        p[t.second]++;
        if(res[cnt] != t.first){
          cnt++;
          res[cnt] = t.first;
        } 
    }

}

int main(){

    cin >> n >> T;

    for(int i = 1;i <= n; ++ i){
        cin >> a[i];
    }

    if(n == 1){
        cout << (int)pow(a[1],T) << endl;
        return 0;
    }

    merge(T);

    cout << res[T] << endl;

    return 0;
}

3.序列

给定 m个序列,每个包含 n个非负整数。
现在我们可以从每个序列中选择一个数字以形成具有 m个整数的序列。
很明显,我们一共可以得到 nm个这种序列,然后我们可以计算每个序列中的数字之和,并得到 nm个值。
现在请你求出这些序列和之中最小的 n个值。

多路归并
这样子思考::当问题简化为两个数组,两个数组任取两个数求和,求最小值。当a数组有序。可分组:b[ i ] + (a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ],a[ 5 ] … ,a[ 6 ])这个序列也是有序的。所以这个问题就可以看作是多个有序数组,合并成一个有序数组(多路归并)

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;

const int M = 2050;

typedef pair<int,int> PII;

int a[M],b[M],c[M];

int n,m,T;
void merge(){

    priority_queue<PII, vector<PII>, greater<PII>>q;
    for(int i = 0;i < n; ++i){
        q.push({a[0] + b[i], 0});
    }

    for(int i = 0;i < n; ++i){
        auto t = q.top();
        q.pop();
        c[i] = t.first;
        q.push({t.first - a[t.second] + a[t.second + 1],t.second + 1});
    }

    for(int i = 0;i < n; ++i) a[i] = c[i];

}

int main(){

    cin >> T;

    while(T--){
       cin >> m >> n;
       for(int i = 0;i < n; ++i) cin >> a[i];
       sort(a,a+n);
       for(int j = 1;j <= m-1; ++j){
        
          for(int i = 0;i < n; ++i) cin >> b[i];
          merge();
       
       }

       for(int i = 0;i < n;++i) cout << a[i] << ' ';
       cout << endl;
        
    }

    return 0;

}
  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值