TP
思路:
-
比较特别的二分答案题。通常的思路是题目要求什么就二分答案什么。但此题二分 最多能提高多少攻击力 是不可行的,因为根据这个 “答案” 你没法确定每个技能升级多少次,跟 M 无法联系,也就不存在 check 关系。
-
正解是二分 最后一次升级技能提升了多少攻击力。
-
我们升级技能的朴素过程,肯定是贪心的思路,找到所有技能中攻击力最高的,升级它,再改变它的点数。可以发现,当我们知道了最后一次升级技能提升了多少攻击力,由于之前升级技能的贪心过程,之前升级技能提升的攻击力都不少于 该次,而升级技能点数减少的过程是一个等差数列,我们显然能 O ( 1 ) O(1) O(1) 的时间知道每个技能升级了几次。最后根据升级技能的次数和 M 对比,check 关系就出来了。
-
知道了 每个技能升级的次数,显然也可以推导出答案最多可以提高多少点攻击力。
-
还有些细节问题:check 时,累计的是升级技能攻击力 大于 mid 的次数。算答案时,先累计优先升级比最后一次攻击力高的,再累计相同的。
C o d e : Code: Code:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define debug(x) cout<<"target is "<<x<<endl
#define forr(a,b,c) for(int a=b;a<=c;a++)
#define all(a) a.begin(),a.end()
#define oper(a) operator<(const a& ee)const
#define endl "\n"
#define ul (u << 1)
#define ur (u << 1 | 1)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 100010, M = 200010, MM = 110;
int INF = 0x3f3f3f3f, mod = 1e9 + 7;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
ll a[N], b[N];
bool check(int mid) {
ll sum = 0;//统计次数
for (int i = 1; i <= n; i++) {
if (a[i] <= mid)continue; //不统计攻击力等于 mid 的升级
sum += (a[i] - mid - 1) / b[i] + 1;
}
return sum > m;
//大于 m 时是不可取的,小于等于逼近
}
ll cot(ll be, ll ed, ll xi) {
return (be + ed) * xi / 2;
}
ll cal(int mi) { //计算答案
int summi = 0;//统计攻击力等于 mid 的升级的次数
ll sum = 0;
for (int i = 1; i <= n; i++) {
if (a[i] < mi)continue;
if ((a[i] - mi) % b[i] == 0)summi++;
if (a[i] == mi)continue;
//贪心,一开始 sum 先加攻击力大于 mid 的升级
//首项末项项数
ll xi = (a[i] - mi - 1) / b[i] + 1;
ll ed = a[i] - (xi - 1) * b[i];
sum += cot(a[i], ed, xi);
m -= xi;
}
//如果还有多余的升级次数,再升级 攻击力等于 mid 的技能
while (m && summi) {
m--; summi--;
sum += mi;
}
return sum;
}
void solve() {
cin >> n >> m;
forr(i, 1, n) {
cin >> a[i] >> b[i];
}
//二分 最后一次升级技能提升了多少攻击力
int l = 1, r = 1e6 + 10;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid))l = mid + 1;
else r = mid;
}
cout << cal(l);
}
int main() {
cinios;
int T = 1;
forr(t, 1, T) {
solve();
}
return 0;
}