zoukankan      html  css  js  c++  java
  • 【POJ1821】Fence

    单调队列优化dp

    我们将每个人的s值排序,这样我们就能保证当前这个人刷的木板一定在上一个人之后,我们就能进行线型dp

    定义f[i][j]表示前i个人刷前j个木板获得的最多报仇,那么有

    1. 第i个人不工作,此时f[i][j]=f[i-1][j]
    2. 第j个木板空着,此时f[i][j]=f[i][j-1]
    3. 第i个人刷[k+1,j]木板,由题意得k+1≤Si≤j并且j-k≤Li,于是存在状态转移方程

    在dp过程中,我们假定外层变量i为定值,当j增大时,不难发现k的取值范围上界不变,下界变大。我们不妨比较一下两个决策k1,k2,假设k1<k2≤Si-1

    因为k2的位置靠后,所以k1最更早的被排除,如果此时满足

    说明k2不仅更优,而且它存活的时间更长,我们就可以将k1排除。

    因此,我们可以建立一个单调队列,存储决策允许集合并且保证决策点k单调递增,数值f[i-1][k]-Pi*k单调递减的序列。每次我们取出队头决策(最优)进行转移即可。

    所以,我们就可以设计dp解决问题了

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long ll;
     7 inline int read() {
     8     int ret=0;
     9     int op=1;
    10     char c=getchar();
    11     while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();}
    12     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
    13     return ret*op;
    14 }
    15 struct node {
    16     int l,s,p;
    17     bool operator <(const node &x) const {
    18         return s<x.s;
    19     }
    20 }a[110];
    21 int n,m,f[110][16010];
    22 int q[16010],l,r;
    23 inline int calc(int i,int k) {
    24     return f[i-1][k]-a[i].p*k;
    25 }
    26 int main() {
    27     n=read(); m=read();
    28     for(int i=1;i<=m;i++) {
    29         a[i].l=read();
    30         a[i].p=read();
    31         a[i].s=read();
    32     }
    33     sort(a+1,a+m+1);
    34     for(int i=1;i<=m;i++) {
    35         l=1,r=0;
    36         for(int k=max(0,a[i].s-a[i].l);k<=a[i].s-1;k++) {
    37             while(l<=r&&calc(i,k)>=calc(i,q[r])) r--;
    38             q[++r]=k;
    39         }
    40         for(int j=1;j<=n;j++) {
    41             f[i][j]=max(f[i-1][j],f[i][j-1]);
    42             if(j>=a[i].s) {
    43                 while(l<=r&&j-a[i].l>q[l]) l++;
    44                 if(l<=r) f[i][j]=max(f[i][j],calc(i,q[l])+j*a[i].p);
    45             }
    46         }
    47     }
    48     printf("%d
    ",f[m][n]);
    49     return 0;
    50 }
    AC Code
  • 相关阅读:
    11.爱吃皮蛋的小明(斐波那契数列)
    10.二叉树最大宽度和高度
    9.二叉树的序遍历
    8.递归第一次
    6.数的计算(递归算法)
    5.十进制转m进制
    数论——快速幂(C++)
    最短路径——SPFA算法(C++)
    最小环——Floyd变种算法(C++)
    数论——质因数分解(C++)
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10989144.html
Copyright © 2011-2022 走看看