队列优化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]);
}
posted @ 2020-10-23 19:33  林生。  阅读(60)  评论(0)    收藏  举报