P4377 [USACO18OPEN]Talent Show

一开始他还不是题解,是草稿……

题解

\(x_i\) 表示第 \(i\) 个点选或不选,可得

\[ans=max(\frac{ \sum_{i=1}^{n}(x_i\times t_i)}{\sum_{i=1}^{n}(x_i\times w_i)}) \]

我们不妨设一个函数如下

\[y=ans\times \sum_{i=1}^{n}(x_i\times w_i)-\sum_{i=1}^{n}(x_i\times t_i) \]

我们以 \(ans\) 为自变量,\(y\) 为因变量,剩下的表达式的所有取值为常量,我们就可以画出 \(2^n\) 方个函数图像,我们可以简单画一下函数图像(随便画的几根线)。

首先,可以得到的是,这个 \(ans\) 要成立的话是要有一条函数的在取自变量为当前 \(ans\) 的情况下取 \(0\) 。(十分显然,不然就不满足我们上面的第一个式子了)

同时我们需要 \(ans\) 最大,所以我们需要找到最右边的一个满足条件的 \(ans\) ,在本图中就是黄色直线与 \(y\) 轴的交点。

然后我们考虑如何找出这个交点,可以发现,对于一个固定的 \(ans\) ,我们可以通过求所有函数的最小值与 \(0\) 的关系来求解。如果最小值小于 \(0\) ,那么 \(ans\) 偏小;如果大于 \(0\) ,那么 \(ans\) 偏大;如果等于,那么就是答案。发现这个东西是满足单调性的,可以二分求解;同时求最小值的操作是可以 \(dp\) 的,复杂度是满足的。

但是这道题目还给我们添加了一个限制条件,即重量和必须大于等于 \(W\) ,我们可以考虑在 \(dp\) 的时候添加限制条件。我们设\(f_{i,j}\) 表示到第 \(i\) 个点,且重量和为 \(j\) 时的最小值是什么,我们可以发现 \(w_i\) 的值很大,但是 \(W\) 的值很小,所以我们只需要维护 \(1000\) 就可以了,大于 \(1000\) 的都放在一千。

以上。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=255,W=1005;
int n,w;
struct Cow{int w,t;}s[N];
double f[W];
double l,r,mid,ans;
bool check(double now)
{
	f[0]=0;
	for(int i=1;i<=w;++i) f[i]=1e9+7;
	for(int i=1;i<=n;++i)
	{
		for(int j=w;j>=0;--j)
		f[min(j+s[i].w,w)]=min(f[min(j+s[i].w,w)],f[j]+now*s[i].w-s[i].t);
	}
	return f[w]<=0;
}
int main()
{
	cin>>n>>w;
	for(int i=1;i<=n;++i) scanf("%d%d",&s[i].w,&s[i].t);
	l=0,r=250000;
	while(r-l>1e-4)
	{
		// printf("%lf %lf\n",l,r);
		mid=(l+r)/2;
		if(check(mid))
		l=ans=mid;
		else r=mid;
	}
	printf("%d\n",(int)(ans*1000));
}
posted @ 2020-09-11 15:54  Point_King  阅读(112)  评论(0编辑  收藏  举报