E – Amusement Park
题目描述:
给定
n
个数a[i]
,可以进行k
次操作,每次操作都可以选择a
数组中的任意一个数a[i]
,获得他的值a[i]
,并把a[i]-1
放回原数组问最多能获得多大的价值?
思路:
考虑二分答案
可以把题目转换成:给定
个数,值为 ,然后从中挑选 k
个最大的数,然后求和因为是挑最大的
k
个数,我们可以二分这k
个数中的最小值mid
,我们只需要求一下,判断与 k
的大小关系即可二分完以后,计算最终答案还是需要注意一下,因为最小值可能只取几个,所以先计算最小值+1以上的数,剩下的数量再加最小值
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
ll n, m, k;
ll tr[MAX];
bool check(ll mid){
m = 0;
for(int i = 1; i <= n; ++i){
m += max(0ll, tr[i] - mid);
}
if(m < k)return true;
else return false;
}
void work(){
cin >> n >> k;
for(int i = 1; i <= n; ++i){
cin >> tr[i];
}
ll l = 0, r = 2000000001;
while (l <= r) {
ll mid = (l + r) / 2;
if(check(mid))r = mid - 1;
else l = mid + 1;
}
ll ans = 0;
++l;
for(int i = 1; i <= n; ++i){
if(tr[i] < l)continue;
k -= (tr[i] - l + 1);
ans += max(0ll, (tr[i] - l + 1) * (tr[i] + l) / 2);
}
--l;
while (k--) {
ans += l;
}
cout << ans << endl;
}
int main(){
io;
work();
return 0;
}