[POJ2976] Dropping tests
Posted qixingzhi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POJ2976] Dropping tests相关的知识,希望对你有一定的参考价值。
传送门:>Here<
题意:给出长度相等的数组a和b,定义他们的和为$dfrac{a_1+a_2+...+a_n}{b_1+b_2+...+b_n}$。现在可以舍弃k对元素(一对即$a[i]和b[i]$),问最大的和是多少?
解题思路
01分数规划入门题(并没有学过,看到hy大佬在刷因此也去学了下)
问题可以转化为数组中的每个元素选或不选,也就可以认为每一个元素都乘上一个$x[i], x[i] ∈ {0, 1}$
因此问题可以转化为$ans = dfrac{sumlimits_{i = 1}^{n}a[i] * x[i]}{sumlimits_{i = 1}^{n}b[i] * x[i]}$
将除法转化为加法$sumlimits_{i = 1}^{n}a[i] * x[i] - ans * sumlimits_{i = 1}^{n}b[i] * x[i] = 0$
合并得$sumlimits_{i = 1}^{n}(a[i]-ans*b[i])*x[i] = 0$
当$x$数组的取值确定时,可以发现函数$f(r) = sumlimits_{i = 1}^{n}(a[i]-r*b[i])*x[i]$是减函数,因此可以二分$r$。当前取到的$r$能够满足$sumlimits_{i = 1}^{n}(a[i]-r*b[i])*x[i] geq 0$即为可行,为了满足此条件,肯定要让选择的那些元素的和越大越好,因此可以建立数组$d[i] = a[i]-r*b[i]$并排序,选择最大的加起来验证是否大于等于0.
Code
long long
/*By DennyQi 2018.8.12*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; #define int long long const int MAXN = 10010; const int MAXM = 27010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) + (x << 1) + c - ‘0‘, c = getchar(); return x * w; } struct Score{ int idx; double sc; }s[MAXN]; int N,K; int a[MAXN],b[MAXN]; double L,R,Mid,d[MAXN]; inline bool comp(const Score& a, const Score& b){ return a.sc < b.sc; } inline bool judge(double _r){ for(int i = 1; i <= N; ++i){ d[i] = (double)((double)(a[i]) - (double)(1.0*_r*b[i])); } sort(d+1,d+N+1); double res = 0.0; for(int i = N; i > K; --i){ res += d[i]; } return res >= 0.0; } #undef int int main(){ #define int long long for(;;){ N = r, K = r; if(!N && !K) break; for(int i = 1; i <= N; ++i) a[i] = r; for(int i = 1; i <= N; ++i) b[i] = r; L = 0.000, R = 9999999999.999; while(R - L >= 1e-8){ Mid = (L + R) / 2.000; if(judge(Mid)){ L = Mid; } else{ R = Mid; } } for(int i = 1; i <= N; ++i){ s[i] = (Score){i, (double)((double)(a[i]) - (double)(1.0*L*b[i]))}; } sort(s+1,s+N+1,comp); int fz=0,fm=0; for(int i = N; i > K; --i){ fz += a[s[i].idx]; fm += b[s[i].idx]; } double rs = (double)fz/(double)fm; printf("%.0f ", rs * 100); } return 0; }
以上是关于[POJ2976] Dropping tests的主要内容,如果未能解决你的问题,请参考以下文章
POJ-2976 Dropping tests---二分最大化平均值