整体思路:
将现有牌数进行排序,先记录下此时最小牌数min,
那么想要增加一套牌,牌数最小的数字必须加一张手写牌
随后把牌数更新,同时判断后续牌数有没有也是min的;
如果没有就说明本次加入手写牌后整体就增加一套牌
如果有(例如初始牌数都是一样的)那就不急着增加套牌数,对这个牌进行同样的操作
注意事项:开long long
参考代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; ll a[N];//a[i]是指 第i种牌最多能手写 a[i]张 //利用 multimap 以牌数进行排序,key会出现重复的情况 multimap<int,int> p;//对组p<某号牌现有的牌数,这组牌的初始下标> 初始下标是为了后续访问a[i] ll n,m; //ans是记录利用手写牌所能增加的套牌数,sum是记录初始时有多少套牌数 //最终的数就是二者之和 ll ans = 0,sum = 0; void way(){//统计ans if(m<=0) return;//已经没有手写牌了,就返回 auto bg = p.begin();//bg指向当前最小牌数的pair对组 int min = bg->first;//记录最小值方便后续判断是否算得上增加了一套牌 int dex = bg->second;//拿到这组牌的初始下标,便于访问a[i]查看他最多能加入几张手写牌 if(a[dex]>0){//只有剩余纸张大于0(m>0前面已经判断)且这个号牌还能加入手写牌(a[i]>0) 才加入手写牌 a[dex]--;//还能加入的手写牌数减1 m--;//总的纸张数减1 int temp = min; temp++; //拿到他已有的牌数 加一张手写牌 p.erase(bg);//删除原来的数据 p.insert(pair<int,int>(temp,dex));//加入现在更新的数据 bg = p.begin();//重新让bg指向此时最小数牌的pair对组 } else {//无法再加入手写牌就返回 return; } if(bg->first!=min) {//现在的最小牌数跟加入手写牌前的最小牌数不同 ans++;//增加的这一张手写牌可以让套牌数加1 } way();//继续上述操作直到无法再加入手写牌 } void solve(){ //数据初始化 cin>>n>>m; for(int i=0;i<n;i++){ int j; cin>>j;//初始牌数,i为初始下标与a[i]对应 p.insert(pair<int,int>(j,i)); } sum = p.begin()->first;//拿到初始的套牌数 就是牌数最少的那个号牌的数量 for(int i=0;i<n;i++){ cin>>a[i];//a[i]记录对应牌的手写牌数量上限 } way();//统计手写牌的加入能增加几个套牌数---ans cout<<ans + sum;//总套牌数 = 初始套牌数 + 手写牌增加的套牌数 } int main(){ solve(); return 0; }
0.0分
4 人评分
【偶数求和】 (C语言代码)记得sum的归零时机浏览:989 |
C语言程序设计教程(第三版)课后习题7.1 (C语言代码)浏览:766 |
C语言训练-求1+2!+3!+...+N!的和 (C语言代码)浏览:2498 |
永远的丰碑 (C语言代码)浏览:698 |
C语言程序设计教程(第三版)课后习题5.7 (C语言代码)浏览:723 |
C语言程序设计教程(第三版)课后习题9.6 (C语言代码)浏览:597 |
用筛法求之N内的素数。 (C++代码)浏览:754 |
1009题解浏览:802 |
【亲和数】 (C语言代码)浏览:628 |
C语言程序设计教程(第三版)课后习题10.3 (C语言代码)浏览:523 |