D - Fence POJ - 单调队列优化-DP

  • D - Fence

  •  POJ - 1821 
  • 题意:现在有n个地板需要画,同时有k个工人分别坐在S[i]位置上。每个工人只能画他周围最多L[i]个位置,如果画必须画上S[i]位置,每画一个可得到P[i]的金钱。求总的最大金钱。
  • 思路:dp[i][j] 表示前i个工人画到第j个地板所得到的最大金钱。
  • 那么dp[i][j] = max(dp[i][j-1],dp[i-1][j]) 
  • (假设当前第i个工人不画第j个位置,那么dp[i][j] 就等于前i个工人画到第j-1个或者前i-1个工人画到第j个的最大值),如果画上第j个位置,则dp[i][j] = max(dp[i-1][k]+(j-k)*P[i],dp[i][j]),k是枚举的上一个工人画到什么位置 
  • dp[i-1][k]+(j-k)*P[i]可以写成j*P[i] 与 dp[i-1][k]-k*P[i]的和而想办法枚举j时就能解决掉 dp[i-1][k]-k*P[i]这个式子的最大值
  • 采用单调队列维护最大值,但是不可全部进入队列同时也不可全部进行这个dp[i][j]的更新,因为第i个人控制的范围有限
  • 所以当j<num[i].s去单调队列维护k值,因为现在准备更新的是第i个人一定要涂了所以 前i-1个人所涂的不能超过num[i].s
  • 单调队列不断维护最大值即可与此相对的是第i个人可以更新的范围j从num[i].s开始到队列中的值+L最终输出dp[k][n]即可
  • #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    using namespace std;
    #define maxn 16666
    #define ll long long
    int n,k;
    ll dp[111][maxn];
    pair<int,ll>que[maxn];
    struct node
    {
        int l,p,s;
    } num[111];
    bool cmp(node a,node b)
    {
        return a.s<b.s;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&k))
        {
            for(int i=1; i<=k; i++)
                scanf("%d%d%d",&num[i].l,&num[i].p,&num[i].s);
            sort(num+1,num+1+k,cmp);
            int head,tail;
            memset(dp,0,sizeof(dp));
            for(int i=1; i<=k; i++)
            {
                head=1;
                tail=0;
                que[++tail]=make_pair(0,0);
                for(int j=1; j<=n; j++)
                {
                    dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
                    if(j<num[i].s)
                    {
                        while(head<=tail&&que[tail].second<dp[i-1][j]-j*num[i].p)tail--;
                        que[++tail]=make_pair(j,dp[i-1][j]-j*num[i].p);
                    }
                    else
                    {
                        while(head<=tail&&que[head].first+num[i].l<j)head++;
                        if(head<=tail)
                            dp[i][j]=max(dp[i][j],que[head].second+j*num[i].p);
                    }
                }
            }
            printf("%lld\n",dp[k][n]);
        }
        return 0;
    }
    

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/83187515