luogu 4377 Talent show 01分数规划+背包dp

时间:2023-03-09 16:15:50
luogu 4377 Talent show 01分数规划+背包dp

01分数规划+背包dp

将分式下面的部分向右边挪过去,通过二分答案验证,

注意二分答案中如果验证的mid是int那么l=mid+1,r=mid-1,double类型中r=mid,l=mid;

背包dp中注意所有大于W的要通过min和max将答案归于W,通过dp得到该种情况的最大结果,不能用贪心

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
inline int read(){
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;}
namespace zjc{
int n,W,w[],t[];
double v[],f[];
bool solve(double mid){
rep(i,,W) f[i]=-inf;
rep(i,,n) v[i]=t[i]-w[i]*mid;
rep(i,,n)dec(j,W,) f[min(w[i]+j,W)]=max(f[min(w[i]+j,W)],f[j]+v[i]);
return f[W]>=;
}
void work(){
n=read(),W=read();
double l=,r=;
rep(i,,n) w[i]=read(),t[i]=read(),r+=t[i];
while(r-l>=1e-){
double mid=(l+r)/;
if(solve(mid)) l=mid;
else r=mid;}
printf("%d",(int)l*);return;
}
}
int main(){
zjc::work();
return ;
}