题意:给出n个a和b,让选出n-k个数对( a i , b i a_i,b_i ai,bi)使得 ∑ a [ i ] ∑ b [ i ] \frac{∑a[i]}{∑b[i]} ∑b[i]∑a[i]最大
analysis
01分数规划模板题
但又不是完全的模型,有一点小变化:
主要就在只能选n-k个,而模型里面,存在的一组解 x 1 , x 2 , x 3 . . . x n x_1,x_2,x_3...x_n x1,x2,x3...xn中并没有对 ∑ x i \sum x_i ∑xi有限制
但是好像问题不大,因为根据上面的推导, ∑ ( a i − L × b i ) x i \sum (a_i-L\times b_i)x_i ∑(ai−L×bi)xi要取到最大值的话,就是要选大的 a i − L × b i a_i-L\times b_i ai−L×bi,那么如果我们把 a i − L × b i a_i-L\times b_i ai−L×bi从大到小排个序的话,很显然如果只选前k个不能够使和大于0的话就不满足题意了(也可以从本来选定的n-k个xi的角度出发分析这个问题)
还有一个问题是在写二分的judge函数的时候,到底是要大于排序还是要小于排序?
回顾01规划二分的推导过程:
也就是说,如果存在一组解 x i x_i xi使得
∑ i = 1 n ( a i − L × b i ) x i > = 0 \sum_{i=1}^{n}(a_i-L\times b_i)x_i>=0 i=1∑n(ai−L×bi)xi>=0
那么我们当前二分的这个L比原式的最大值要小,即
∃ x 1 , x 2 . . . x n , 使 得 ∑ i = 1 n a i × x i ∑ i = 1 n b i × x i > = L \exist{x_1,x_2...x_n},使得\\ \frac{\sum_{i=1}^{n}a_i\times x_i}{\sum_{i=1}^{n}b_i\times x_i}>=L ∃x1,x2...xn,使得∑i=1nbi×xi∑i=1nai×xi>=L
既然是存在一组解存在一组解 x i x_i xi,我们就应该去构造存在的那组解,那么肯定就是取最大值喽
code
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <bitset>
#include <ctime>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define ll long long
template<typename T>void read(T &x){
x=0;char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
const int maxn=1000+10;
int n,k;
ll a[maxn],b[maxn];
double c[maxn];
inline bool cmp(double a,double b){return a>b;}
inline double calc(double L){
double res=0;
loop(i,1,n) c[i]=1.0*a[i]-1.0*b[i]*L;
sort(c+1,c+1+n,cmp);
loop(i,1,n-k) res+=c[i];
return res;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif
while(1){
read(n);
read(k);
if(n==0&&k==0)
break;
clean(a,0);
clean(b,0);
clean(c,0);
loop(i,1,n)read(a[i]);
loop(i,1,n)read(b[i]);
double R=1,L=0,eps=1e-14,ans=0;
while(R-L>=eps){
double mid=(R+L)/2;
if(calc(mid)>0) L=mid;
else R=mid;
}
printf("%.0lf\n",L*100);
}
return 0;
}