您的位置:首页 > 其它

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

2015-11-19 20:52 731 查看
#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
;
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的>_<。

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息