首页 > 代码库 > 【HDU4803】Poor Warehouse Keeper 数学+贪心

【HDU4803】Poor Warehouse Keeper 数学+贪心

#include <stdio.h>
int main()
{
	puts("转载请注明出处[vmurder]谢谢");
	puts("网址:blog.csdn.net/vmurder/article/details/43450731");
}


题意:

初始状态为:1个物品,总价为1。

目标状态为:x个物品,总价为y。


操作A:变为x+1,y+y/x。(y不取整)

操作B:变为x,  y+1   


问最少多少步可以达成条件?(最后操作结束后对y取整)

如果不行输出-1。


题解:

先说"-1"

    首先如果x<=y,,那么我们可以先一直做操作一,使得状态变为(x,x),然后暴力给y+1

一定可以达成,所以只需要在x>y时输出"-1"就好了。


然后是x<=y的情况。


我们考虑操作A的次数是固定的~~

那么就应该让操作B尽量少,也就是让单价尽量快地到达要求。

那么就应该尽早采取操作B。

于是就有了下述策略:

计算当前单价为a,目标单价为b,然后此时一次操作B能给单价增加多少~

然后从小到大枚举当前数量,尽可能多地使用操作B。


呃,这样的话样例3输出12~~~

所以我们就应该考虑只要采取了k次操作B以后总价不会超过目标价格+1-eps就好了~~


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10
#define eps 1e-9
using namespace std;
int main()
{
	freopen("test.in","r",stdin);
	int i,j,k;
	double x,y;
	while(scanf("%lf%lf",&x,&y)!=EOF)
	{
		if(x-y>eps)
		{
			puts("-1");
			continue;
		}
		int ans=(int)(x+eps-1);
		double now=1.0;
		double sum=0.0;
		for(i=1;i<=(int)(x+eps);i++)
		{
			sum=now*i;
			k=(int)(y/x*i-sum);
			ans+=k;
			now+=(double)k/i;
			if((sum+k+1)/i*x-y<1.0)
			{
				now+=1.0/i;
				ans++;
			}
		}
		if(now<(double)y/x)ans++;
		printf("%d\n",ans);
	}
	return 0;
}


【HDU4803】Poor Warehouse Keeper 数学+贪心