POJ 1821 Fence(单调队列优化)

【题意】K个人对N块木板涂色,每个人初始站在一块木板前(不重复),每人最多只能涂包含所站木板的连续l个木板或一个木板也不涂。给出每人最多涂的木块数l,涂一快木板的工钱p,站的木板s。求这群人最多共获得多少工钱。


【分析】dp[i][j]表示前i个人对前j块木板操作的最大收益。

核心状态转移方程:dp[i][j]=max(dp[i][j-1],dp[i-1][k]+P[i].p*(j-k),dp[i-1][j]),max(0,P[i].s-P[i].l)<=k

显然直接做就是枚举i,j,k。那么这里显然是TLE,特别要踢到的是事刚刚的转移里面k的范围的边界一定要确定好,不然等着WA!

现在来推导一下单调队列优化的核心式子,dp[i][j]=max(dp[i-1][k]+p[i]*p*(j-k)),展开后边,并且把p[i].p*j移到方程左边来,那么这个方程变成了dp[i][j]-j*p[i].p=max(dp[i-1][k]-k*p[i].p),那么这里显而易见了,在枚举k的时候,P[i].p*j的值已经确定不用考虑,只需要找出使(dp[i-1][k]-P[i].p*k)最大的k就行了,又观察到这个式子的值不与j相关,也就是说在枚举k之前我们就可以通过某种方法找出这个k,即:构造递减的 单调队列 维护k值。当然还是有个小坑的,坑了我一下午!


【AC代码】


【ps】该去赤饭了~~~


//you are my sunshine.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 16050;
const int maxm = 150;
int dp[maxm][maxn];
int que[maxn];
struct node{
    int l,p,s;//l每个最多涂的木板数,p涂一块木板需要多少钱,s一个人所在的木板
    node(){}
    node(int l,int p,int s):l(l),p(p),s(s){}
    bool operator<(const node &rhs)const{
        return s0?(p[i].s-p[i].l):0;
            for(int j=1; j<=N; j++){
                dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
                if(j>=p[i].s+p[i].l) continue; //涂不了
                //maintain queue.
                while(head

你可能感兴趣的:(ACM/ICPC_POJ,ACM/ICPC单调队列)