5281: [Usaco2018 Open]Talent Show
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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 ",ans); return 0; }
This passage is made by Iscream-2001.