有一个长度为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();
}