Fence

Fence

有一个长度为n的([1,n])墙,有k位工人,第i位工人有参数(s_i,p_i,l_i),意思该位工人可以刷包含(s_i)的长度小于等于(l_i)的区间,报酬为区间长度乘以(p_i),墙的一个位置不能被重复刷,问最大的报酬之和,(1 <= n <= 16 000,1 <= k <= 100)

注意到k * n才十万,不难想到设(f[i][j])表示前i位工人刷前j个位置的最大报酬之和,注意到我们要保证递推的无后效性,于是我们得把工人的(s_i)排序,因此有

[f[i][j]=max(f[i-1][j],f[i][j-1],max_{j-l_ileq kleq s_i}f[i-1][k]+(j-k) imes p_i) ]

注意到在i一定时,决策范围都是呈单调性,且j与k无关,于是可以使用单调队列优化,注意判边界即可,时间复杂度(O(nk))

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define ri register
using namespace std;
struct inter{
	int l,p,s;
	il bool operator<(const inter&x)const{
		return s<x.s;
	}
}I[150];
int dp[150][16050],T[20050],L,R;
il void read(int&);
template<class free>
il free Max(free,free);
int main(){
	int N,K;
	read(N),read(K);
	for(int i(1);i<=K;++i)
		read(I[i].l),read(I[i].p),read(I[i].s);
	sort(I+1,I+K+1);
	for(int i(1),j;i<=K;++i){
		L=1,R=0;
		for(j=0;j<=N;++j){
			while(L<=R&&T[L]<j-I[i].l)++L;
			dp[i][j]=Max(dp[i][j-1],dp[i-1][j]);//麻烦解释一下,这里明显越界了,但是改成不越界反而a不掉了
			if(L<=R&&j>=I[i].s)dp[i][j]=Max(dp[i][j],dp[i-1][T[L]]+(j-T[L])*I[i].p);
			if(j<I[i].s){
				while(L<=R&&dp[i-1][j]-j*I[i].p>=dp[i-1][T[R]]-T[R]*I[i].p)--R;
				T[++R]=j;
			}
		}
	}printf("%d",dp[K][N]);
	return 0;
}
template<class free>
il free Max(free a,free b){
	return a>b?a:b;
}
il void read(int &x){
	x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
	while(c>='0'&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10961964.html