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 <deque>
#include <algorithm>
#define il inline
#define ri register
using namespace std;
il void read(int&);
struct pi{
    int x,y;
};
struct worker{
    int l,p,s;
    il bool operator<(const worker&x)const{
        return s<x.s;
    }
    il void read(){
        ::read(l),::read(p),::read(s);
    }
}w[110];
deque<pi>D;
int dp[110][16010];
template<class free>il free Max(free,free);
int main(){
    int n,k;read(n),read(k);
    for(int i(1);i<=k;++i)w[i].read();
    sort(w+1,w+k+1);
    for(int i(1);i<=k;++i){
        D.clear();
        for(int j(0);j<=n;++j){
            while(D.size()&&j-D.front().y>w[i].l)D.pop_front();
            dp[i][j]=Max(dp[i-1][j],dp[i][j-1]);
            if(D.size()&&j>=w[i].s)dp[i][j]=Max(dp[i][j],D.front().x+j*w[i].p);
            if(j<w[i].s){
                while(D.size()&&dp[i-1][j]-j*w[i].p>=D.back().x)D.pop_back();
                D.push_back((pi){dp[i-1][j]-j*w[i].p,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();
}
上一篇:POJ 2189


下一篇:Scene视图辅助线绘制