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_i\leq k\leq s_i}f[i-1][k]+(j-k)\times 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();
}

posted @ 2019-06-02 09:26  a1b3c7d9  阅读(307)  评论(0编辑  收藏  举报