小蓝最近正在玩一款 RPG 游戏。他的角色一共有 N个可以加攻击力的技能。
其中第 i 个技能首次升级可以提升 Ai 点攻击力, 以后每次升级增加的点数都会减少 Bi。Ai/Bi (上取整) 次之后, 再升级该技能将不会改变攻击力。
现在小蓝可以总计升级 M 次技能, 他可以任意选择升级的技能和次数。请 你计算小蓝最多可以提高多少点攻击力?
思路一:暴力写法,优先队列(60pts)
将技能数值插入大根堆,取出后减去Bi在放回堆中。
#include <bits/stdc++.h>//暴力写法,堆O(mlogn) #define int long long using namespace std; int n, m, ans; priority_queue<pair<int, int> > q; bool operator < (const pair<int, int> &a, const pair<int, int> &b) { return a.first < b.first; } signed main() { cin >> n >> m; for (int i = 1; i <= n; i ++) { int x, y; cin >> x >> y; q.push(make_pair(x, y)); } for (int i = 1; i <= m; i ++) { int x = q.top().first, y = q.top().second; q.pop(); ans += x; if (x - y > 0) q.push(make_pair(x - y, y)); } cout << ans; }
思路二:二分(100pts)
每次用一个技能后都会减去Bi,我们要升级m次,可以理解为n个不同的等差数列合并,取其中最大的m个。
给你一堆数,找其中最大的m个数求和,我们考虑用二分的做法,二分第m大的数x, check部分的工作是找到大等于x的个数cnt,如果大等于m, 记录答案,更新l;如果小于m,更新r。这样就可以找到x。
在累加答案的过程中,注意x可能重复,所以我们先对大于x的数累加(等差数列求和公式),统计个数cnt,那么最后剩余m-cnt个x再加到答案上去。
(注意二分的写法,这里采用的是while(l<=r) l=mid+1,r=mid-1, 同时用x记录可能的答案mid)。
#include <bits/stdc++.h>//二分 #define int long long using namespace std; const int N = 1e5 + 10; int n, m, A[N], B[N], ans; bool check(int x) {//找大等于x的个数 int cnt = 0; for (int i = 1; i <= n; i ++) { if (A[i] < x) continue; int k = (A[i] - x) / B[i]; cnt += k + 1; } if (cnt >= m) return 1; else return 0; } signed main() { cin >> n >> m; for (int i = 1; i <= n; i ++) { cin >> A[i] >> B[i]; } int l = 0, r = 1e6 + 10, x; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) l = mid + 1, x = mid; else r = mid - 1; } int cnt = 0; for (int i = 1; i <= n; i ++) { if (A[i] < x) continue; int k = (A[i] - x) / B[i]; if ((A[i] - x) % B[i]) k ++; cnt += k; ans += ((2 * A[i] - (k - 1) * B[i]) * k / 2); } ans += (m - cnt) * x; cout << ans; }
标签:二分,升级,cnt,2129,Bi,蓝桥,int,技能 From: https://www.cnblogs.com/love-lzt/p/18577041