2017ICPCECIC MJF wants to work

来源:互联网 发布:怎么做淘客软件 编辑:程序博客网 时间:2024/06/05 01:52

MJF wants to work

时间限制: 1 Sec  内存限制: 128 MB
提交: 75  解决: 15
[提交][状态][讨论版]

题目描述

MJF feel the summer vacation is very leisure. So he wants to work to earn money.
There are n jobs MJF can take part in.For job i, it has the start time ti.x, the end time ti.y and reward ci.
MJF wants to take part in two jobs (exact two jobs), and he wants to earn exactly M yuan. He doesn't want to earn one money more,he thinks it's a waste.
Becase MJF is a lazy boy, so he wants the time of the sum of two jobs shortest.
Becase MJF can only take part in one job in a time.So two jobs can't overlap.(ti.y < tj.x)

输入

The input consists of multiple test cases. 
For each test,the first line contains 2 integers n, m.(1 <= n, m <= 2e5)
Then following n lines, each line contains 3 integers ti.x, ti.y, ci.(1 <= ti.x, ti.y, ci <= 2e5)

输出

For each test case, print the value of the sum of two jobs' time.if there are no answer,please print"oh no!"

样例输入

3 101 2 33 4 74 6 71 101 10 10

样例输出

4oh no!

提示

来源

2017ICPCECIC

[提交][状态]


先说说题意,某某某人想去挣钱,只想整m元,多了少了都不行(不太正常),有n个工作可以去干(不知道哪个学校毕业的,本菜如果有个工作就贼开心),然后还不想多浪费时间(这和我有点像),必须干两个活,让你去帮他先择工作,看看有没有正好的。

跟着中石油集训的时候做到了这一道题,我天,疯狂超时,想着。。。

觉得像贪心,那就开始排序,已每个工作的开始时间进行了个排序,然后就开始找,去暴力啦,果然超时,很伤心。

想了想,可以按c(工资)分以下类,因为如果这一份工作的工资确定了,另一份就必须得是那些钱了,然后加上map< int , vector<pair< int,int > >  >,结果还是超时,队有想起来,直接找间隔时间最小的,慢慢找上去,加上二分查找啥的,废了半天劲,写出来了,报了个wa,mmp,这就尴尬了,一脸绝望。

赛后看题解,我天,还能这么玩。。。

把以线段为基本单位改成已点为基本单位,把任务时长/金钱啥的关联上去,加上左右端点的标志位,然后就可以按时间点排序,时间点小的在左边,如果一样,左端点在左边,这样可以解决.(ti.y < tj.x)这种情况,接下来

按照点的时间排序

如果是左端点,就去找和这个线段(点和线段由结构体关联上了)匹配的任务的最小时间,这个时候在剩余工资的那个类里面全是可行解,只需要维护一个当前最小时间的值就行。

如果是右端点则去更新这个线段所在类别的时间最小值.(更新最小值其实就是相当于是前面的将这个任务加入类中)

这里推荐一个博客http://blog.csdn.net/mmy1996/article/details/76407613


ac代码:

#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <set>#include <map>using namespace std;const int maxn=2e5+10;const int inf=0x3f3f3f3f;int n,m,nodecnt;int dp[maxn];struct node{int xy;int tim;int mon;int dj; }nn[2*maxn];bool cmp(node A,node B){if(A.xy != B.xy)return A.xy < B.xy;elsereturn A.dj < B.dj;}int main(){while(~scanf("%d%d",&n,&m)){int x,y,c;nodecnt=0;for(int i=1;i<=n;i++){scanf("%d%d%d",&x,&y,&c);nn[++nodecnt].xy=x;nn[nodecnt].tim=y-x+1;nn[nodecnt].mon=c;nn[nodecnt].dj=0;nn[++nodecnt].xy=y;nn[nodecnt].tim=y-x+1;nn[nodecnt].mon=c;nn[nodecnt].dj=1; }sort(nn+1,nn+1+nodecnt,cmp);int ans=inf;memset(dp,0x3f,sizeof(dp));for(int i=1;i<=nodecnt;i++){if(nn[i].dj==0){ans=min(ans,dp[m-nn[i].mon]+nn[i].tim);}else{dp[nn[i].mon]=min(dp[nn[i].mon],nn[i].tim);}} if(ans==inf)printf("oh no!\n");elseprintf("%d\n",ans);}return 0;}

左端点时选择去判断加上这个区间解是否可以更优,碰到右端点去更新一下dp。

经过不断更新和维护,可以把一个个区间加进去,一点点更新,保证最小,有点几分像dp思想,不过不知道这是什么方法。