題解:這題顯然是一個線性動規,那麼肯定是第一時間想到設f[i]:1~i的最大空閒時間,但是,想了一下之後發現,第i時刻的最大空閒時間是和後面i+選擇任務的持續時間的時刻有關係的,那麼,正着找肯定是不行的,我們來試一下倒着搜,即設f[i]表示i~n的最大空閒時間,經嘗試,發現是完全可行的,可以列出動態轉移方程如下
(本時刻無任務)f[i]=f[i+1]+1;//繼承上一個時刻的最大空閒時間後+1
(本時刻有任務)f[i]=max(f[i],f[i+a[sum])//a[sum]表示在這個時刻的任務的持續時間,找出選擇哪一個本時刻任務使空閒時間最大化
那麼既然是倒着搜,從後往前的任務對應的開始時間自然也要反過來,從大到小排序(同時也是爲了把相同開始時間的任務放到一起),當然在進行狀態刷新的時候別忘了拿sum不斷計一下已經到哪一個任務了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10001;
ll sum[maxn],dp[maxn];
struct ren
{
ll ks,js;
};
ren z[maxn];
bool cmp(ren a,ren b)
{
return a.ks>b.ks;
}
int main()
{
ll n,k;
cin>>n>>k;
for(int i=1;i<=k;i++){
cin>>z[i].ks>>z[i].js;
sum[z[i].ks]++;
}
sort(z+1,z+k+1,cmp);
ll num=1;
for(int i=n;i>=1;i--){
if(sum[i]==0){
dp[i]=dp[i+1]+1;
}else{
for(int j=1;j<=sum[i];j++){
if(dp[i+z[num].js]>dp[i]){
dp[i]=dp[i+z[num].js];
}
num++;
}
}
}
cout<<dp[1]<<endl;
return 0;
}