废话不多说。dp方程很好写,dp[i][j]=max(dp[i-1][k]+cost[i]*(j-k))。当然也可以省略一维节省内存。然后这个N*K*N的算法必然TLE所以说要想优化。开始想的单调队列优化啊但是总想不清楚那个实现的过程。也想过要倒着枚举j,但是立即想到这前的k还没算出来呢。所以说被自己给否了。其实仔细想想就好了。对于第i个worker来说,它能够达到的最右边界是worker[i].s+worker[i].l-1。那么对于这个状态,它只能从dp[woker[i].s-1]这个状态转移过来。而对于下一个j来说,就只能从dp[worker[i].s-1]和dp[worker[i].s-2]这两个状态转移过来。而对于这两者中取得较大值的左边界来说,右边的j同时减1以后还是另下一个j取得最大值的解。而再跟dp[worker[i].s-3]进行比较的就应该是这个最大值了。所以说可以用一个数组记录下worker[i]的左边界,不断地更新它。因为是一次移动1,所以能够做到保证不重不漏。
注意一下初始化。我开始忘记了j-worker[i].l<=0的情况。你为什么就那么理所当然地认为减了以后还是大于0的呢???!!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
const int maxm = 20000;
int n,k;
struct node
{
int p,l,s;
}worker[maxn];
int res[maxn];
int dp[maxm];
inline bool cmp(const node&a,const node&b)
{
return a.s<b.s;
}
int main()
{
int i,j,t;
// freopen("in2.txt","r",stdin);
while(scanf("%d%d",&n,&k)!=EOF)
{
worker[0].s = 0;
for(i = 1;i<=k;i++)
scanf("%d%d%d",&worker[i].l,&worker[i].p,&worker[i].s);
sort(worker,worker+k+1,cmp);
memset(dp,0,sizeof(dp));
// int tmp = min(worker[1].l,worker[2].s-1);
for(i = worker[1].s;i<=worker[1].l;i++)
dp[i] = worker[1].p*i;
for(i = 2;i<=k;i++)
{
res[i] = worker[i].s;
if(dp[worker[i].s-1]>0&&dp[worker[i].s-1]+worker[i].p*worker[i].l>dp[t = worker[i].s+worker[i].l-1])
dp[t] = dp[worker[i].s-1]+worker[i].p*worker[i].l;
// printf("%d/n",t);
for(j = t-1;j>=worker[i].s;j--)
{
if(res[i]-1>0&&dp[res[i]-1]>0&&dp[res[i]-1]+worker[i].p*(j-res[i]+1)>dp[j])
dp[j] = dp[res[i]-1]+worker[i].p*(j-res[i]+1);
else if(res[i]-1<=0)dp[j] = max(dp[j],worker[i].p*j);
if(j-worker[i].l>0&&dp[j-worker[i].l]>0&&dp[j-worker[i].l]+worker[i].p*worker[i].l>dp[j])
dp[j] = dp[j-worker[i].l]+worker[i].p*worker[i].l,res[i] = j-worker[i].l+1;
else if(j-worker[i].l<=0&&worker[i].p*j>dp[j])
dp[j] = worker[i].p*j;//,res[i] = j-worker[i].l+1;
}
}
int ans = 0;
for(i = 1;i<=n;i++)
ans = max(ans,dp[i]);
/* for(i = 1;i<=n;i++)
printf("%d/n",dp[i]);*/
printf("%d/n",ans);
}
return 0;
}