[USACO18OPEN]Talent Show--01分数规划+背包

Luogu 4377

在这里插入图片描述

题目分析:

  • 仍然:设 s u m = ∑ t [ i ] , t o t = ∑ w [ i ] sum=\sum{t[i]},tot=\sum{w[i]} sum=t[i],tot=w[i]

  • 转化为使 s u m t o t 最 大 , 并 且 t o t > = W \frac{sum}{tot}最大,并且tot>=W totsum,tot>=W

  • 设最优值为 a n s ans ans,则有:
    s u m t o t &lt; = a n s \frac{sum}{tot}&lt;=ans totsum<=ans
    s u m − t o t ∗ a n s &lt; = 0 sum-tot*ans&lt;=0 sumtotans<=0
    ∑ ( t [ i ] − w [ i ] ∗ a n s ) &lt; = 0 \sum{(t[i]-w[i]*ans)}&lt;=0 (t[i]w[i]ans)<=0

  • 二分 a n s ans ans,注意 r = 1 0 6 r=10^{6} r=106,用 01 01 01背包判定

Code:

#include <bits/stdc++.h>
using namespace std;
#define maxn 300
#define maxV 1010
#define re register
#define INF 2139062143

int n,V,w[maxn],t[maxn];
long long f[maxV];

inline void init_() {
	freopen("a.txt","r",stdin);
}

inline int read_() {
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	return x*f;
}

inline bool pd_(int x) {
    memset(f,128,sizeof(f));
    f[0]=0;  
    long long pdc=f[V];
	for(re int i=1;i<=n;++i) {
		for(re int j=V;j>=0;--j) {
			if(f[j]==pdc) continue;
			int jj=j+w[i];
			if(jj>V) jj=V;
			f[jj]=max(f[jj],f[j]+t[i]-(long long)w[i]*x);
		}
	}
	if(f[V]>=0) return true;
	else return false;	
} 

void readda_() {
	n=read_();V=read_();
	for(re int i=1;i<=n;++i) {
		w[i]=read_();
		t[i]=read_();
		//r=max(r,(t[i]/w[i])*1000);
		t[i]*=1000;
	} 
	int l=0,r=1e6,ans,mid;
	while(l<=r) {
		mid=(l+r)>>1;
		if(pd_(mid)) {
			l=mid+1;
			ans=mid;
		}
		else r=mid-1;
	}
	printf("%d",ans);
}

int main() {
	init_();
	readda_();
	return 0;
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值