P1280 尼克的任务
题意:
尼克的一个工作日为N分钟,从第一分钟开始到第N分钟结束。
当尼克到达单位后他就开始干活。如果在同一时刻有多个任务需要完成,
尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,
则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,
则这些任务也由尼克的同事完成。如果某任务于第P分钟开始,持续时间为T分钟,
则该任务将在第P+T-1分钟结束。
写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间
一道普及难度的题
靠
我居然想不到正解!!
我TMDP太弱了。。。
还是要多练啊。。。
设f[i]:1~i的最大空闲时间,但是,第i时刻的最大空闲时间是和后面i+1选择任务的持续时间的时刻有关系的(有后效性),那么,正着找肯定是不行的,
我们来试一下倒着搜,即设f[i]表示i~n的最大空闲时间,经尝试,发现是完全可行的,可以列出动态转移方程如下
(本时刻无任务)f[i]=f[i+1]+1;//继承上一个时刻的最大空闲时间后+1
(本时刻有任务)f[i]=max(f[i],f[i+a[sum])//a[sum]表示在这个时刻的任务的持续时间,找出选择哪一个本时刻任务使空闲时间最大化
那么既然是倒着搜,从后往前的任务对应的开始时间自然也要反过来,从大到小排序(同时也是为了把相同开始时间的任务放到一起),
当然在进行状态刷新的时候别忘了拿sum不断计一下已经到哪一个任务了
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define love_nmr 0 int n,k; struct node { int beg; int dis; friend bool operator < (const node &a,const node &b) { return a.beg>b.beg; } }w[10505]; int f[10505]; int t[10505]; int main() { ios::sync_with_stdio(false); cin>>n>>k; for(int i=1;i<=k;i++) { cin>>w[i].beg>>w[i].dis; t[w[i].beg]++; } sort(w+1,w+k+1); int ji=1; for(int i=n;i>=1;i--) { if(!t[i]) f[i]=f[i+1]+1; else { for(int j=1;j<=t[i];j++) { if(f[i]<f[i+w[ji].dis]) f[i]=f[i+w[ji].dis]; ji++; } } } cout<<f[1]; return 0; }
----olinr