当前位置: 代码迷 >> 综合 >> 二分+贪心 Codeforces614D Skills
  详细解决方案

二分+贪心 Codeforces614D Skills

热度:32   发布时间:2023-12-14 03:28:18.0

传送门:点击打开链接

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

思路:枚举达到A分的科目数,然后再二分得到剩下的钱,让最低分最大是多少。

首先,肯定要把科目的所有分数排序一次,然后枚举达到满分的科目时,肯定是从大到小去枚举的。

然后再看剩下的钱数,去二分m,m表示最低分最大是多少。那么问题在check上,然后处理好check就行了~

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;const int MX = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;PII A[MX];
int W, cf, cm, n, prt[MX];
LL m, sum[MX];bool check(LL m, int x, int p) {p = min(upper_bound(A + 1, A + 1 + n, PII(x, W)) - A - 1, p - 1);LL tot = (LL)p * x - sum[p];return tot <= m;
}int get(LL money, int p) {int l = 1, r = W, m;if(!check(money, l, p)) return 0;while(l <= r) {m = (l + r) >> 1;if(check(money, m, p)) l = m + 1;else r = m - 1;}return l - 1;
}int main() {//FIN;while(~scanf("%d%d%d%d%I64d", &n, &W, &cf, &cm, &m)) {sum[0] = 0;for(int i = 1; i <= n; i++) {scanf("%d", &A[i].first);A[i].second = i;}sort(A + 1, A + 1 + n);for(int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + A[i].first;}int ansa = 0, ansb = get(m, n + 1);LL s = m, ans = (LL)ansb * cm;for(int i = n, j = 1; i >= 1; i--, j++) {s -= W - A[i].first;if(s < 0) break;int t = get(s, i);LL temp = (LL)j * cf + (LL)t * cm;if(temp > ans) {ans = temp; ansa = j; ansb = t;}}printf("%I64d\n", ans);for(int i = n, j = 1; i >= 1; i--, j++) {if(j <= ansa) prt[A[i].second] = W;else prt[A[i].second] = max(A[i].first, ansb);}for(int i = 1; i <= n; i++) {printf("%d%c", prt[i], i == n ? '\n' : ' ');}}return 0;
}