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<min(P[i].s-1,j)

显然直接做就是枚举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 <set>
#include <map>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
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 s<rhs.s;
    }
}p[maxn];

int main(){
    int N,K;
    while(~scanf("%d%d",&N,&K)){
        for(int i=1; i<=K; i++){
            scanf("%d%d%d",&p[i].l,&p[i].p,&p[i].s);
        }
        sort(p+1,p+K+1);
        //INIT
        memset(dp,0,sizeof(dp));
        int head,tail;
        //DP.

        for(int i=1; i<=K; i++){
            head=0,tail=1;
            que[head] = (p[i].s-p[i].l)>0?(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<tail&&que[head]+p[i].l<j) head++; //队列中的k过小
                if(j<p[i].s) //符合k的取值范围可以考虑入队
                {
                    int temp=dp[i-1][j]-j*p[i].p;
                    while(head<tail&&dp[i-1][que[tail-1]]-que[tail-1]*p[i].p<temp) tail--;
                    que[tail++] = j;
                    continue;//优化的前提是第i个人不可以涂这些模板,坑啊,这里我TLE了很久很久!!!
                }
                dp[i][j] = max(dp[i][j],dp[i-1][que[head]]+p[i].p*(j-que[head]));
            }
        }
        printf("%d\n",dp[K][N]);
    }
    return 0;
}


你可能感兴趣的:(POJ 1821 Fence(单调队列优化))