题目来源:蓝桥杯2022初赛 C++ C组I题
题目描述
小蓝最近正在玩一款RPG 游戏。他的角色一共有N个可以加攻击力的技能。
其中第i个技能首次升级可以提升Ai点攻击力,以后每次升级增加的点数都会减少Bi。
⌈Ai/Bi⌉ (向上取整) 次之后,再升级该技能将不会改变攻击力。
现在小蓝可以总计升级M次技能,他可以任意选择升级的技能和次数。
请你计算小蓝最多可以提高多少点攻击力?
输入格式
输入第一行包含两个整数N和M。
以下N行每行包含两个整数Ai和Bi。
对于40% 的评测用例,1 ≤ N, M ≤ 1000;
对于60% 的评测用例,1 ≤ N ≤ 10^4; 1 ≤ M ≤ 10^7;
对于所有评测用例,1 ≤ N ≤ 10^5,1 ≤ M ≤ 2 × 10^9,1 ≤ Ai; Bi ≤ 10^6。
输出格式
输出一行包含一个整数表示答案。
输入样例
3 6
10 5
9 2
8 1
输出样例
47
问题分析
用二分法来解决。
AC的C++语言程序如下:
/* LQ0142 技能升级 */
#include
#include
#include
using namespace std;
const int N = 100000;
int n, m;
long long a[N], b[N], t[N];
bool judge(long long x)
{
long long cnt = 0;
for (int i = 0; i < n; i++)
if (a[i] >= x) {
cnt += (a[i] - x) / b[i] + 1;
if (cnt >= m) return true;
}
return false;
}
int main()
{
long long tcnt = 0;
cin >>n >> m;
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
tcnt += a[i] / b[i] + (a[i] % b[i] ? 1 : 0);
}
m = tcnt < m ? tcnt : m;
int l = 0, r = *max_element(a, a + n) + 1;
while (l < r) {
int mid = (l + r + 1) / 2;
if (judge(mid)) l = mid;
else r = mid - 1;
}
long long ans = 0;
for (int i = 0; i < n; i++)
if (a[i] >= l) {
int cnt = (a[i] - l) / b[i] + 1;
int last = a[i] - (cnt - 1) * b[i];
if (last == l) {
cnt--;
last += b[i];
}
ans += (a[i] + last) * cnt / 2;
m -= cnt;
}
cout << ans + m * l << endl;
return 0;
}