http://codeforces.com/problemset/problem/613/B
题意:
有n个数,可以将其中一个数字加一,最多操作m次。给出最大值A,给出cf,cm。设等于A的数的个数为k,最小值为min,那么答案为k * cf + min * cm。求最大的答案,并输出最后的n个数。
排序,从大的一端枚举将多少数变为A,二分最小值,然后在小的一端二分查找可以使多少数变为最小值,更新答案。
懵逼,二分写搓了真容易被卡。
/* Footprints In The Blood Soaked Snow */
#include <cstdio>
#include <utility>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 100005;
int n, A, cf, cm, val[maxn];
LL m, sum[maxn];
pii num[maxn];
inline bool check(int x, LL left, int mr) {
int l = 1, r = mr;
while(l <= r) {
int mid = l + r >> 1;
if(num[mid].first <= x) l = mid + 1;
else r = mid - 1;
}
return (LL)r * x - sum[r] <= left;
}
int main() {
scanf("%d%d%d%d%I64d", &n, &A, &cf, &cm, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &num[i].first);
num[i].second = i;
}
sort(num + 1, num + 1 + n);
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + num[i].first;
LL ans = -1, maxtot = 0, minval = 0;
for(int i = 0; i <= n; i++) {
LL left = m - ((LL)i * A - (sum[n] - sum[n - i]));
if(left < 0) break;
int l = 0, r = A;
while(l <= r) {
int mid = l + r >> 1;
if(check(mid, left, n - i)) l = mid + 1;
else r = mid - 1;
}
LL res = (LL)i * cf + (LL)r * cm;
if(res > ans) {
ans = res;
maxtot = i;
minval = r;
}
}
for(int i = 1; i <= n; i++)
if(n - maxtot < i) val[num[i].second] = A;
else if(num[i].first <= minval) val[num[i].second] = minval;
else val[num[i].second] = num[i].first;
printf("%I64d\n", ans);
for(int i = 1; i <= n; i++) printf("%d ", val[i]);
return 0;
}