题目描述
小P踩着厚厚的积雪,踏入了一片雪山的神秘领域。这里是高耸入云的雪山之巅,寒风凛冽,温度骤降。随着海拔的升高,环境变得更加恶劣,但也正是这样的环境,孕育出了许多珍贵的灵芝。这些灵芝顽强地生长在寒冷的环境中,环境越恶劣,它们的品质更加优良,疗效更加卓越。
共有 n n n 座雪山,第 i i i 座雪山的最高海拔为 h i h_i hi 米,山峰上海拔第 1 ∼ h i 1\sim h_i 1∼hi 米的位置都有一株灵芝,海拔越高疗效越好。
小P最多可以采摘 k k k 株灵芝,由于小P的包太小,每次只能装下一株灵芝。也就是说,小P每次上山只能够采摘一株灵芝,摘完之后就得下山。
请你帮小P计算,满足所有采摘的灵芝都尽可能优良的前提下,小P上山的总攀登里程为多少米?
注意:对于不同的雪山,海拔相同的灵芝品质也相同。
输入格式
第一行 2 2 2 个正整数 n , k n, k n,k ,表示雪山的数量与最多可以采摘的灵芝数量。
第二行是 n n n 个正整数,第 i i i 个数字表示第 i i i 座雪山的最高海拔 h i h_i hi。
提示:输入量较大,建议使用更加快速的输入方式。
输出格式
一个整数,表示满足所有采摘的灵芝都尽可能优良的前提下,小P上山的总攀登里程为多少米。
样例输入 1
3 5
100 50 102
样例输出 1
502
样例输入 2
2 2023
2 3
样例输出 2
9
样例输入 3
5 114
514 528 526 517 522
样例输出 3
58266
数据范围
测试点 | n n n | k k k |
---|---|---|
1 ∼ 4 1\sim 4 1∼4 | 1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100 | 1 ≤ k ≤ 100 1\leq k\leq 100 1≤k≤100 |
5 ∼ 8 5\sim 8 5∼8 | 1 ≤ n ≤ 2000 1\leq n\leq 2000 1≤n≤2000 | 1 ≤ k ≤ 2000 1\leq k\leq 2000 1≤k≤2000 |
9 ∼ 16 9\sim 16 9∼16 | 1 ≤ n ≤ 1 0 6 1\leq n\leq 10^6 1≤n≤106 | 1 ≤ k ≤ 1.1 × 1 0 7 1\leq k\leq 1.1\times 10^7 1≤k≤1.1×107 |
17 ∼ 20 17\sim 20 17∼20 | 1 ≤ n ≤ 1 0 6 1\leq n\leq 10^6 1≤n≤106 | 1 ≤ k ≤ 2 × 1 0 9 1\leq k\leq 2\times 10^9 1≤k≤2×109 |
对于所有测试点,均满足 1 ≤ h i ≤ 2 × 1 0 9 1\leq h_i\leq 2\times 10^9 1≤hi≤2×109。
样例解释
样例一中,第 1 1 1 座山选择了 2 2 2 株灵芝,分别在海拔第 100 100 100 米 与第 99 99 99 米。第 3 3 3 座山选择了 3 3 3 株灵芝,分别在海拔第 102 102 102, 101 101 101, 100 100 100 米,共 502 502 502 米。
解析
二分法,详见代码:
#include<bits/stdc++.h>
using namespace std;
int n, k;
int h[1000005];
long long ans = 0;
//取海拔x及以上的灵芝是否不超过要求,不超过返回true,超过返回fals
bool check(long long x) {
long long sum = 0;
for(int i = 1; i <= n; i++) {
if (h[i] >= x) { //当前山峰大于等于x
sum += h[i] - x + 1; //将x及以上的灵芝都采了
}
if (sum > k) return false; //若超过需求,返回false
}
return true;//否则返回true
}
int main() {
cin >> n >> k;
for(int i = 1; i <= n; i++) { //输入
cin >> h[i];
}
long long left = 0;
long long right = 2e9 + 1; //肯定不够
while(left + 1 < right) { //二分求刚好不能满足需求的最低海拔(right)
long long mid = (left + right) / 2;
if (check(mid) == true) {
right = mid;
} else {
left = mid;
}
}
for(int i = 1; i <= n; i++) { //将right及以上的灵芝都采了,计算攀登里程
if (h[i] >= right) {
k -= h[i] - right + 1; //计算剩余灵芝数量
ans += (right + h[i]) * (h[i] - right + 1) / 2;
}
}
if (right > 1) { //补足剩余灵芝
ans += (right - 1) * k;
}
cout << ans;
return 0;
}