P2045 - [蓝桥杯2022初赛] 消除游戏 - New Online Judgehttp://oj.ecustacm.cn/problem.php?id=2045
暴力能过40%的数据。。。
#include <bits/stdc++.h>
#define a first
#define b second
using namespace std;
typedef long long ll;
typedef pair<int, int> pll;
const int N = 1e5 + 4;
multiset<pll>s;
int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++) {
pll temp;
cin >> temp.a >> temp.b;
s.insert(temp);
}
ll ans = 0;
while (m > 0 && !s.empty()) {
pll cur = *s.rbegin();
s.erase(*s.rbegin());
ans += cur.a;
m--;
cur.a -= cur.b;
if (cur.a > 0) {
s.insert(cur);
}
}
cout << ans;
return 0;
}
正解是二分枚举最后一次攻击力最高能加多少,并且要注意最后的计算不能把等于这个值的直接加在答案里:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+4;
ll n, m;
ll a[N] = {0}, b[N] = {0};
// 最后一次加攻击能不能到x
ll check(ll x) {
ll cnt = 0;
for(int i=0; i<n; i++) {
if (a[i] >= x) {
cnt += (a[i] - x) / b[i] + 1;
if (cnt >= m) {
return 1;
}
}
}
return 0;
}
// 二分枚举最后一次攻击力最高能加多少
int getHighestLast() {
int low = 0, high = 1e6;
while(low < high) {
int mid = (low + high + 1) >> 1;
if (check(mid)) { // 如果mid可以
low = mid;
} else {
high = mid-1;
}
}
return low;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
ll totalCnt = 0;
for(int i=0; i<n; i++) {
cin >> a[i] >> b[i];
if (a[i] % b[i] == 0) {
totalCnt += a[i] / b[i];
} else {
totalCnt += a[i] / b[i] + 1;
}
}
m = min(m, totalCnt);
int highestLast = getHighestLast();
ll ans = 0;
for (int i=0 ; i<n; i++) {
if (a[i] >= highestLast) {
int cnt = (a[i] - highestLast) / b[i] + 1;
int last = a[i] - (cnt-1) * b[i];
if (last == highestLast) {
cnt--;
last += b[i];
}
ans += (a[i] + last) * cnt >> 1;
m -= cnt;
}
}
cout << ans + m * highestLast;
return 0;
}