5281: [Usaco2018 Open]Talent Show
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 79 Solved: 58
[Submit][Status][Discuss]
Description
FarmerJohn要带着他的N头奶牛,方便起见编号为1…N,到农业展览会上去,参加每年的达牛秀!他的第i头奶牛重量为wi,才艺水平为ti,两者都是整数。在到达时,FarmerJohn就被今年达牛秀的新规则吓到了:
(一)参加比赛的一组奶牛必须总重量至少为W
(这是为了确保是强大的队伍在比赛,而不仅是强大的某头奶牛),并且
(二)总才艺值与总重量的比值最大的一组获得胜利。
FJ注意到他的所有奶牛的总重量不小于W,所以他能够派出符合规则(一)的队伍。帮助他确定这样的队伍中能够达到的最佳的才艺与重量的比值。
Input
输入的第一行包含N和W。下面N行,每行用两个整数wi和ti描述了一头奶牛。
1≤N≤250
1≤W≤1000
1≤wi≤10^6
1≤ti≤10^3
Output
请求出Farmer用一组总重量最少为W的奶牛最大可能达到的总才艺值与总重量的比值。
如果你的答案是A,输出1000A向下取整的值,以使得输出是整数
(当问题中的数不是一个整数的时候,向下取整操作在向下舍入到整数的时候去除所有小数部分)。
Sample Input
3 15
20 21
10 11
30 31
20 21
10 11
30 31
Sample Output
1066
在这个例子中,总体来看最佳的才艺与重量的比值应该是仅用一头才艺值为11、重量为10的奶牛,但是由于我们需
要至少15单位的重量,最优解最终为使用这头奶牛加上才艺值为21、重量为20的奶牛。这样的话才艺与重量的比值
为(11+21)/(10+20)=32/30=1.0666666...,乘以1000向下取整之后得到1066。
在这个例子中,总体来看最佳的才艺与重量的比值应该是仅用一头才艺值为11、重量为10的奶牛,但是由于我们需
要至少15单位的重量,最优解最终为使用这头奶牛加上才艺值为21、重量为20的奶牛。这样的话才艺与重量的比值
为(11+21)/(10+20)=32/30=1.0666666...,乘以1000向下取整之后得到1066。
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=5281
Solution
一看题面就知道要01分数规划。。。
假设答案为c,式子比较显然 ti的总和 / wi的总和 >= c
ti的总和 >= wi的总和 * c
然后就是二分c验证正确性。。
将每只牛的价值赋值为 ti - wi * c
显然如果有一种方案使得总的牛的价值不小于0,就说明c存在合法方案。。
由于W<=1000,我们可以直接DP。。
f [ i ] 表示wi总和不小于i时的最大价值总和。。
f [ i ] = max(f[j]+val)其中val表示当前牛的价值,并且i-j<=w
由于i和j的关系,要用单调队列维护。。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<cmath>
#include<set>
#define pa pair<LL,LL>
#define LL long long
#define ept 1e-5
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void Out(int a){
if(a>9) Out(a/10);
putchar(a%10+'0');
}
const double inf=1e9;
const LL mod=1e9+7;
const int N=300;
int n,m,cnt=1,W;
struct cow{
int w,s;
}a[N];
double f[2000],t[2000];
int q[2000]; int main(){
n=read();W=read();
for(int i=1;i<=n;++i){
a[i].w=read();a[i].s=read();
}
double l=0,r=10000,mid,y;
int x,L=1,R=0;
while(fabs(r-l)>ept){
//cout<<l<<" "<<r<<endl;
mid=(l+r)/2;
for(int i=0;i<=W;++i) f[i]=-inf;
f[0]=0;
for(int i=1;i<=n;++i){
x=a[i].w<=W?a[i].w:W;
y=(double)a[i].s-(double)mid*(double)a[i].w;
L=1;R=1;q[1]=0;
for(int j=1;j<=W;++j){
while(L<=R&&f[j]>f[q[R]]) --R;
q[++R]=j;
while(j-q[L]>x) ++L;
t[j]=f[q[L]]+y;
}
for(int j=1;j<=W;++j)
if(t[j]>f[j]) f[j]=t[j];
}
if(f[W]>=0) l=mid;
else r=mid;
}
l=l*1000;
int ans=l;
printf("%d\n",ans);
return 0;
}
This passage is made by Iscream-2001.