题目
思路
设
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 个粉刷匠,刷了前
j
j
j 个木块(可以有木块不选)
然后转移不刷
f
i
,
j
=
m
a
x
(
f
i
,
j
−
1
,
f
i
−
1
,
j
)
f_{i,j}=max(f_{i,j-1},f_{i-1,j})
fi,j=max(fi,j−1,fi−1,j)
和刷
max
j
−
l
i
≤
k
<
s
i
f
i
−
1
,
k
+
p
i
×
(
j
−
k
)
\max_{j-l_i≤k<s_i}f_{i-1,k}+p_i\times(j-k)
j−li≤k<simaxfi−1,k+pi×(j−k)
的情况
接着,把 j j j 提出来,发现后面的部分求最大值可以用单调队列,然后就优化了时间复杂度。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int f[200010],x[200010];
int q[200010],wz[200010];
int n,m;
struct node
{
int l,p,s;
}a[200010];
bool cmp(const node&x,const node&y)
{
return x.s<y.s;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
scanf("%d%d%d",&a[i].l,&a[i].p,&a[i].s);
sort(a+1,a+1+m,cmp);
for(int i=1; i<=m; i++)
{
int le=max(a[i].s-a[i].l,0),ri=min(a[i].s+a[i].l,n);
int h=1,t=0;
for(int j=le; j<=ri; j++)
x[j]=f[j]-a[i].p*j;
for(int j=le; j<a[i].s; j++)
{
while(h<=t&&q[t]<=x[j])
t--;
q[++t]=x[j];
wz[t]=j;
}
for(int j=a[i].s; j<=ri; j++)
{
while(h<=t&&wz[h]<j-a[i].l)
h++;
if(h>t)
break;
f[j]=max(f[j],q[h]+a[i].p*j);
}
for(int j=2; j<=n; j++)
f[j]=max(f[j],f[j-1]);
}
printf("%d",f[n]);
return 0;
}