1. 程式人生 > >[POJ2976] Dropping tests

[POJ2976] Dropping tests

當前 style truct 們的 left core .org 加法 -s

傳送門:>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{\sum\limits_{i = 1}^{n}a[i] * x[i]}{\sum\limits_{i = 1}^{n}b[i] * x[i]}$

將除法轉化為加法$\sum\limits_{i = 1}^{n}a[i] * x[i] - ans * \sum\limits_{i = 1}^{n}b[i] * x[i] = 0$

合並得$\sum\limits_{i = 1}^{n}(a[i]-ans*b[i])*x[i] = 0$

當$x$數組的取值確定時,可以發現函數$f(r) = \sum\limits_{i = 1}^{n}(a[i]-r*b[i])*x[i]$是減函數,因此可以二分$r$。當前取到的$r$能夠滿足$\sum\limits_{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\n", rs * 100); } return 0; }

[POJ2976] Dropping tests