POJ 2976 Dropping tests

题意:给出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 (aiL×bi)xi要取到最大值的话,就是要选大的 a i − L × b i a_i-L\times b_i aiL×bi,那么如果我们把 a i − L × b i a_i-L\times b_i aiL×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=1n(aiL×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×xii=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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值