题意:有一排墙编号从
DP 啊。
用
即第
即第
即第
但是还是太慢了,考虑优化第三个转移方程,可以得到:
其中遍历
基本操作一波即可,注意一开始先按
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define INF 1e9
using namespace std;
const int maxn=16101,maxk=110;
int n,k;
int head,tail;
int f[maxk][maxn];
struct queue
{
int val;
int pos;
}q[maxn];//单调队列,维护最大f[i-1][k]-p[i]*k
struct worker
{
int l;
int p;
int s;
}a[maxk];
int cmp(worker a,worker b)
{
return a.s<b.s;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
scanf("%d%d%d",&a[i].l,&a[i].p,&a[i].s);
sort(a+1,a+k+1,cmp);
for(int i=1;i<=k;i++)
{
head=1;
tail=0;
for(int j=max(0,a[i].s-a[i].l);j<a[i].s;j++)//把之前的状态先加进去
{
int num=f[i-1][j]-a[i].p*j;
while(head<=tail&&q[tail].val<num)
tail--;
q[++tail].val=num;
q[tail].pos=j;
}
for(int j=1;j<=n;j++)
{
f[i][j]=max(f[i-1][j],f[i][j-1]);//第i个人不涂或第j面墙不涂
if(j<a[i].s||j>=a[i].s+a[i].l)//超出限制
continue;
while(head<=tail&&q[head].pos+a[i].l<j)//删除范围外的
head++;
if(head<=tail)
f[i][j]=max(f[i][j],q[head].val+a[i].p*j);
}
}
printf("%d",f[k][n]);
return 0;
}