bzoj 5281 Talent Show —— 01分数规划+背包
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5281
二分一个答案比值,因为最后要*1000,不如先把 v[] *1000,就可以二分整数;
枚举 mid ,如果 mid 小于等于 ans ,则 ∑v[i] - mid * ∑w[i] >= 0,可以继续往大调整,为了使答案最大,背包找一下使这个值最大的组合,看看能否 >=0;
数组开 1000 即可... 把 w 大于 1000 的直接当做最大的 w 。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mid ((l+r)>>1) using namespace std; typedef long long ll; int const xn=255; int n,m,ans,w[xn]; ll f[1005],tmp[xn],v[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } bool ck(int k) { for(int i=1;i<=n;i++)tmp[i]=v[i]-(ll)w[i]*k; memset(f,-2,sizeof f);// f[0]=0; for(int i=1;i<=n;i++) for(int j=m;j>=0;j--) f[min(m,j+w[i])]=max(f[min(m,j+w[i])],f[j]+tmp[i]); return f[m]>=0; } int main() { n=rd(); m=rd(); for(int i=1;i<=n;i++)w[i]=rd(),v[i]=rd()*1000; int l=1,r=1e9; while(l<=r) { if(ck(mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; }