题意:
意思是,农夫John 有n头牛去参加比赛;今年的比赛有了新的赛制
- 出场的牛的队伍必须要大于等于>=W。
- 在满足第一个条件的情况下获胜的依据是:天赋的总和 / 体重的总和 得出的比值
又文字表述得到的公式是 后来因为要方便比较所以答案要乘以1000。
题解:
首先答案需要得到×1000后的,那么我们可以预处理一下,把 t 的每一项都乘以1000.
要是在有限个里面找出:t越大,w越小那就好了。但是真的那么容易找吗???
每一头牛加进来,对这个比值的影响不可以算出来的,只能枚举所有情况进行处理才行。
真的没有任何办法了吗???
式子通过推导可以得出:
大家观察上面的式子,t 和 w虽然说是给定的,但是总和,选择哪一个是未知的,所以两个总和的值是未知的,
而ans是我们要求出来的,也是未知的。在一个式子里面3个未知数。无法约束得到答案。
其实通过答案就知道我们知道一点东西,其实ans是可以通过二分枚举的。
为什么这么说呢,因为通常求出来答案是小数形式的,80%都是二分得到的。
二分不是需要约束条件吗???
这个条件就是枚举 的状态产生的,首先我们把两个总和看作是常数,
我们是不是可以通过他们之间的大小来二分得到一个值ans的值呢。
现在问题来了:你说可以二分得到,前提是需要知道两个总和。
两个总和都是来自于每一头牛自身的属性,其实是面临着一个小问题,就是在N头牛中选和不选的抉择。
01背包处理这个问题两个总和的问题。
其实我们算出来的ans代入式子 在0的附近浮动。
我们通过check()
- 如果得到的值 大于0 说明ans枚举的小
- 如果得到的值 小于0 说明ans枚举的大
ans可以通过二分枚举,在式子里面其实ans就是一个知道的值,因为枚举出来的过程中把它看作常数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef struct node {
ll t,w;
}node;
node a[2560];
ll n,W;
bool check(ll x){
ll dp[2560];
memset(dp,128,sizeof(dp));
//printf("######\n");
dp[0]=0;
for(ll i=0;i<n;i++){
for(ll j=W;j>=0;j--){
ll t=min(W,a[i].w+j);
dp[t]=max(dp[t], dp[j]+a[i].t-x*a[i].w);
}
}
//printf("####\n");
if(dp[W]>=0) return true;
return false;
}
int main()
{
scanf("%lld%lld",&n,&W);
for(int i=0;i<n;i++){
scanf("%lld%lld",&a[i].w,&a[i].t);
a[i].t*=1000;
}
ll L=0,R=10000005,mid;
ll Ans=0;
while(L<=R){
mid=(L+R)/2;
if(check( mid )){
Ans=mid;
L=mid+1;
}else{
R=mid-1;
}
}
printf("%lld\n",Ans);
}