牛客网暑期ACM多校训练营(第五场)A.gpa 01分数规划

链接:https://www.nowcoder.com/acm/contest/143/A
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

Kanade selected n courses in the university. The academic credit of the i-th course is s[i] and the score of the i-th course is c[i].

At the university where she attended, the final score of her is 

Now she can delete at most k courses and she want to know what the highest final score that can get.

输入描述:

The first line has two positive integers n,k

The second line has n positive integers s[i]

The third line has n positive integers c[i]

输出描述:

Output the highest final score, your answer is correct if and only if the absolute error with the standard answer is no more than 10-5

 

示例1

输入

3 1
1 2 3
3 2 1

输出

2.33333333333

说明

Delete the third course and the final score is 

备注:

1≤ n≤ 105

0≤ k < n

1≤ s[i],c[i] ≤ 10^3 

题目大意:

给出序列s和c,求在最多删除k个课程后\frac{\sum s[i]*c[i]}{\sum s[i]}最大。

分析:

01分数规划模板题,读者可以参看这篇文章https://blog.csdn.net/hhaile/article/details/8883652

这里直接给出这一题的思路

首先根据01分数规划,我们令\frac{\sum s[i]*c[i]}{\sum s[i]}=d,变换后\sum s[i]*(c[i]-d),令p[i]=s[i]*(c[i]-d)

这样只要二分d,对p[i]排序,先取n-k个,剩下的k个只要p[i]<=0时后面的都不需要了(显然是对答案有负贡献的)。

唯一比较麻烦的是精度问题,目测1e-8应该够了(大概)

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include<iomanip>
#include<bitset>
#define lson l,m
#define rson m+1,r
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int maxn = int(1e5) + 100;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = 998244353;
const double eps = 1e-8;
int n, k;
int s[maxn], c[maxn];
double p[maxn];
bool cmp(double a, double b) {
	return a > b;
}
bool check(double mid) {
	for (int i = 0; i < n; i++)
		p[i] = s[i] * (c[i] - mid);
	sort(p, p + n, cmp);
	double ans = 0;
	for (int i = 0; i < n-k; i++)
		ans += p[i];
	for (int i = n - k; i < n; i++)
		if (p[i] > 0)
			ans += p[i];
	if (ans > -eps) return true;
	return false;
}
int main() {
	//ios::sync_with_stdio(false);
	//cin.tie(0);
	//freopen("D:\\cpp\\comper\\3224\\8.in", "r", stdin);
	//freopen("D:\\cpp\\\comper\\8.in", "w", stdout);
	while (~scanf("%d%d", &n, &k)) {
		for (int i = 0; i < n; i++)
			scanf("%d", &s[i]);
		for (int i = 0; i < n; i++)
			scanf("%d", &c[i]);
		double l = 0.0, r = 1000.0;
		while (r - l > eps) {
			double mid = (l + r)*0.5;
			if (check(mid))l = mid;
			else r = mid;
		}
		printf("%.10lf\n", l);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值