题解 尼克的任务

有一种和题解区完全不同的做法。

首先将所有任务按照时间从小到大排序,接着用 \(f_i\) 表示处理前 \(i\) 个任务所能得到的最大空闲时间。

回顾一下需要满足的条件:再某个有任务的时刻,如果尼克是空闲的,就必须从中选择一个任务做。那么我们对于第 \(i\) 个任务,枚举上一个做的任务 \(j\),必须满足的条件是:\(j\) 的结束时间 \(+1\sim\) \(i\) 的开始时间 \(-1\) 没有其他任何事件。并且这样做的价值为 \(len_{j 的结束时间 +1\sim i 的开始时间 -1}\)

这样做的细节也颇多:由于第一个任务不一定是在时刻 \(1\),所以我们得手动设置一个在时刻 \(0\),长度为 \(1\) 的任务,同理需要在设置一个在时刻 \(k+1\) 的任务。

并且为了,满足所有 \(f\) 解出来都是合法的(即不会出现中间有空闲时间但是没做任务的情况),我们先将所有 \(f\) 设置为极小值,再令 \(f_0=0\) 即可。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
inline LL read() {
	LL sum=0,flag=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();}
	while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();}
	return sum*flag;
}

const int N=1e4+10;
int n,k;
int f[N];
struct node {
	int p,t;
}a[N];

int cmp(node x,node y) {
	return x.p<y.p;
}

int main() {
	// freopen("a.in","r",stdin);
	cin>>k>>n;
	for(int i=1;i<=n;i++) cin>>a[i].p>>a[i].t;
	sort(a+1,a+1+n,cmp);
	a[n+1].p=k+1; a[0].t=1;
	memset(f,-0x3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n+1;i++) {
		int lst=0;
		for(int j=i-1;j>=0;j--) {
			if(a[j].p+a[j].t-1<a[i].p) {
				if(lst) {
					if(a[j].p+a[j].t-1>=lst) {
						f[i]=max(f[i],f[j]+max(a[i].p-(a[j].p+a[j].t),0));
					}
				}
				else {
					f[i]=max(f[i],f[j]+max(a[i].p-(a[j].p+a[j].t),0));
				}
			}
			if(!lst&&a[j].p<a[i].p) lst=a[j].p;
		}
	}
	cout<<f[n+1];
	return 0;
}
posted @ 2023-10-08 22:54  2017BeiJiang  阅读(5)  评论(0编辑  收藏  举报