Codeforces614D Skills

题意:n个科目,每个科目最高分为A,现在最多能提高m分。最后权值是两种分数算法之和,第一种算法是达到A分的科目个数*cf,第二种算法是最低分*cm。求提高分数之后,最后的权值最大是多少。并打印出方案。

题解:最大值有x个,最小值为y,那么权值就是w = cf*x+cm*y可以发现这里有两个变量,考虑枚举一个,二分另外一个

#include <bits/stdc++.h>
#define maxn 100010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
ll n, A, cf, cm, m, t1, t2;
pair<ll, ll >a[maxn];
ll sum[maxn], ma;
ll cmp(pair<ll, ll >aa, pair<ll, ll >bb){
    return aa.second<bb.second;
}
ll f(ll x, ll r){
    ll l = 1, pos = -1;
    while(l<=r){
        ll mid = (l+r)>>1;
        if(a[mid].first <= x) l = mid+1, pos = mid;
        else r = mid-1;
    }
    return x*pos-(sum[pos]-sum[0]);
}
int main(){
    scanf("%lld%lld%lld%lld%lld", &n, &A, &cf, &cm, &m);
    for(ll i=1;i<=n;i++)
        scanf("%lld", &a[i].first), a[i].second = i;
    sort(a+1, a+n+1);
    for(ll i=1;i<=n;i++) sum[i] = sum[i-1]+a[i].first;
    for(ll i=0;i<=n;i++){
        ll t = m-(A*i-sum[n]+sum[n-i]);
        if(t < 0) break;
        ll l=1,r=A,mi=-1;
        while(l<=r){
            ll mid = (l+r)>>1;
            if(f(mid,n-i) <= t) l = mid+1, mi = mid;
            else r = mid-1;
        }
        ll temp = mi*cm+cf*i;
        if(ma < temp){
            ma = temp;
            t1 = i;
            t2 = mi;
        }
    }
    for(ll i=1;i<=n;i++){
        if(a[i].first < t2) a[i].first = t2;
        if(n-i+1 <= t1) a[i].first = A;
    }
    sort(a+1, a+1+n, cmp);
    printf("%lld
", ma);
    for(ll i=1;i<=n;i++)
        printf("%lld ", a[i].first);
    return 0;
}
原文地址:https://www.cnblogs.com/Noevon/p/8660043.html