【HDU5188 BestCoder Round 33C】【贪心排序+DP】zhx and contest 考试不被怀疑作弊条件下达到至少m分的最少时间

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=3e6+10,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,m;
struct A
{
	int t,v,l,st;
	bool operator < (const A& b)const {return l-t<b.l-b.t;}//按照耽误时间从小到大排序
}a[32];
int f[N];
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		LL sumv=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d%d",&a[i].t,&a[i].v,&a[i].l);
			a[i].st=max(a[i].l,a[i].t);//st表示最早结束时间
			sumv+=a[i].v;
		}
		if(sumv<m)
		{
			puts("zhx is naive!");
			continue;
		}
		sort(a+1,a+n+1);
		int sumt=0;
		int tmpv=0;
		for(int i=1;i<=n;i++)
		{
			sumt=max(sumt+a[i].t,a[i].l);
			tmpv+=a[i].v;
			if(tmpv>=m)break;
		}
		if(sumt>1e3)while(1);
		memset(f,0,(sumt+2)*4);
		for(int i=1;i<=n;i++)
		{
			for(int j=sumt;j>=a[i].st;j--)if(f[j]<m)//减少不必要的运算,同时防止爆int
			{
				gmax(f[j],f[j-a[i].t]+a[i].v);
			}
		}
		for(int i=0;i<=sumt;i++)if(f[i]>=m)
		{
			printf("%d\n",i);
			break;
		}
	}
	return 0;
}
/*
【trick&&吐槽】
小心a[i].v累加起来爆int哦

【题意】
T(50)组数据,
对于每组数据,有n(1<=n<=30)个问题,
对于第i个问题,如果我们决定去做,那么会花费ti分钟,然后会获得vi的分数。
然而,对于第i道题而言,其解决时间不能早于li(可以等于),否则会被认定为作弊。
1<=ti,li<=1e5;1<=vi<=1e9.
现在我们问你,他至少在场上待多久才可以在不认定为作弊的条件下得到至少m(0<=m<=1e9)分。
如果无法达成,则输出"zhx is naive!"

【类型】
贪心 DP

【分析】
首先,无法达成的条件是当前分数之和<m,这个特判一下,看看要不要输出"zhx is naive!"
否则,肯定至少有一种方法能够达成目标。

我们发现,这题既要决策做哪些题,又要决策做题顺序。
于是,不如我们先假定要做的题已经确定了,现在只是要考虑做题顺序。
这样就会发现,肯定是按照耽误时间从小到大来安排做题顺序。
于是,现在考虑到题的选择,我们先按照耽误时间从小到大来对所有题目做排序。

我们用f[j]表示在当前距离比赛开始过去了j个时间单位条件下能够获得的最大分数。
那么初始化f[]=0,并且有状态转移方程——
for(int i=1;i<=n;i++)
{
	for(int j=sumt;j>=max(a[i].l,a[i].t);j--)gmax(f[j],f[j-a[i].t]+a[i].v);
}

然后枚举一道题做或不做。并且积累在当前时间为j下的分数,记做f[i]。
那么我们就有了状态转移方程gmax(f[i],f[j]+最早从j+1时刻做这道题的最早完成时间)

【时间复杂度&&优化】
O(T*n*sumt),最坏是50*30*30*1e5=45e8的时间复杂度
然而大概是数据太水了,竟然这个复杂度也是可以0msAC的>_<。

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值