队列优化DP
队列优化DP
围栏
有N块木板从左到右排成一行,有M个工匠对这些木板进行粉刷,每块木板至多被粉刷一次。
第 i 个木匠要么不粉刷,要么粉刷包含木板 Si 的,长度不超过 Li 的连续的一段木板,每粉刷一块可以得到 Pi 的报酬。
不同工匠的Si不同。
请问如何安排能使工匠们获得的总报酬最多。
输入格式
第一行包含两个整数N和M。
接下来M行,每行包含三个整数Li,Pi,Si。
输出格式
输出一个整数,表示结果。
数据范围
1≤N≤16000,
1≤M≤100,
1≤Pi≤10000
输入样例:
8 4
3 2 2
3 2 3
3 3 5
1 1 7
输出样例:
17
#include<bits/stdc++.h>
using namespace std;
#define N 16005
#define M 105
int n,m,head,tail,q[N],f[M][N];
struct op
{
int l,p,s;
}t[M];
bool cmp(op a,op b)
{
return a.s<b.s;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i) scanf("%d %d %d",&t[i].l,&t[i].p,&t[i].s);
sort(t+1,t+m+1,cmp);
for(int i=1;i<=m;++i)
{
int l=t[i].l,p=t[i].p,s=t[i].s;
head=1;tail=0;
for(int j=max(0,s-l);j<=s-1;++j)
{
while(head<=tail&&f[i-1][q[tail]]-q[tail]*p<=f[i-1][j]-j*p) tail--;
q[++tail]=j;
}
for(int j=1;j<=n;++j)
{
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(j>=s)
{
while(head<=tail&&q[head]<j-l) head++;
if(head<=tail) f[i][j]=max(f[i][j],f[i][q[head]]+p*(j-q[head]));
}
}
}
printf("%d",f[m][n]);
}

浙公网安备 33010602011771号