zoukankan      html  css  js  c++  java
  • Acwing P298 围栏

    Analysis

    ①首先将所有粉刷匠,按照必须刷的小木块Si从小到大排序.

    上面这个操作为了保证我们可以顺序处理.

    ②我们可以设f[i][j]表示为,前i个粉刷匠,刷了前i个木块.可以有些木块选择不刷

    状态确定好了后,我们分两种情况讨论.

    第i个粉刷匠不工作,那么
    f[i][j]=f[i−1][j]
    第j个木板不刷,那么
    f[i][j]=f[i][j−1]

    .

    结合上面的讨论,我们不难发现,
    f[i][j]=max(f[i−1][j],f[i][j−1])
    接下来的问题就是,如果说粉刷匠工作,而且也还刷第j个木块,那么我们不得不仔细思考.

    对于一个粉刷匠而言,如果说聘请他工作,那么显然我们有几个条件.

    他粉刷的区间长度,至少为1,最多为Li.
    他粉刷的区间内必须包括Si这个小木块.
    粉刷区间左端点,必须小于等于Si
    综上所述我们不妨设置一个粉刷匠粉刷的区域为[k+1,j]
    那么根据上面所说的条件,我们将它转换为数学计算机语言,如下面这个式子所示.
    k+1≤si≤j 1≤j−(k+1)≤Li K≤Si−1
    综上所述,我们可以将状态转移方程一步步出来.

    f[i][j]=maxf[i−1][j],f[i][j−1],f[i][j] f[i][j]=maxj−Li≤k≤Si−1(f[i][j],f[i−1][k]+Pi∗(j−(k+1)+1)) 
    得出了一个朴素的状态转移方程,我们不得不进行转换一下.

    f[i][j]=maxj−Li≤k≤Si−1(f[i][j],f[i−1][k]+Pi∗(j−(k+1)+1)) 
    我们不妨去掉一个括号.

    f[i][j]=maxj−Li≤k≤Si−1(f[i][j],f[i−1][k]+Pi∗(j−k)) 


    上面的一次次变换,让我们发现了,如果说我们要求的f[i][j]要选取到最大值,那么我们核心目标点就是让Max函数内部的

    f[i−1][k]−Pi∗k
    尽量地大.

    尽然如此的话,我们发现K的取值是一个范围,但是我们并不关心这个范围内所有的数值,我们唯一的关心点就是这个范围的最大值.也就是最大的f[i−1][k]
    一个区间,最大值,这些关键字眼,不得不让我们思考一下单调队列这种优秀的数据结构.因此我们把中心放到单调队列上面.

    单调队列的核心要点,就是生存能力的判断.

    我们逐步入手,下面给出几个判断依据.

    我们设当前有两个点,一个是k1,另外一个是k2.

    我们发现当前点,如果说k1<k2,也就是k2后出现.

    我们将k1,k2代入到我们的状态转移方程中的决定部分.

    那么将k1代入

    f[i−1][k1]−Pi∗k1
    再将k2代入其中

    f[i−1][k2]−Pi∗k2
    我们发现如果说我们再满足下面这个条件的话,那么k2一定优于k1

    于是可以用单调队列维护了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define int long long
     7 #define maxn 16000+10
     8 #define maxm 1000+10
     9 using namespace std;
    10 inline int read() 
    11 {
    12     int x=0;
    13     bool f=1;
    14     char c=getchar();
    15     for(; !isdigit(c); c=getchar()) if(c=='-') f=0;
    16     for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    17     if(f) return x;
    18     return 0-x;
    19 }
    20 inline void write(int x)
    21 {
    22     if(x<0){putchar('-');x=-x;}
    23     if(x>9)write(x/10);
    24     putchar(x%10+'0');
    25 }
    26 int n,m;
    27 int deque[maxn];
    28 int dp[maxm][maxn];
    29 struct node
    30 {
    31     int l,p,s;
    32 }x[maxm];
    33 inline bool cmp(node x,node y)
    34 {
    35     return x.s<y.s;
    36 }
    37 inline int calc(int i,int k)
    38 {
    39     return dp[i-1][k]-x[i].p*k;
    40 }
    41 signed main()
    42 {
    43     n=read();m=read();
    44     for(int i=1;i<=m;i++)
    45     {
    46         x[i].l=read();x[i].p=read();x[i].s=read();
    47     }
    48     sort(x+1,x+m+1,cmp);
    49     for(int i=1;i<=m;i++)
    50     {
    51         int head=1,tail=0;
    52         for(int k=max(0ll,x[i].s-x[i].l);k<=x[i].s-1;k++)
    53         {
    54             while(head<=tail&&calc(i,deque[tail])<=calc(i,k)) tail--;
    55             deque[++tail]=k;
    56         }
    57         for(int j=1;j<=n;j++)
    58         {
    59             dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    60             if(j>=x[i].s)
    61             {
    62                 while(head<=tail&&deque[head]<j-x[i].l) head++;
    63                 if(head<=tail)
    64                     dp[i][j]=max(dp[i][j],calc(i,deque[head])+x[i].p*j);
    65             }
    66         }
    67     }
    68     write(dp[m][n]);
    69     return 0;
    70 }

    请各位大佬斧正(反正我不认识斧正是什么意思)

  • 相关阅读:
    C#学习教程
    数据库
    读写信号量
    qt配置tensorflow + opencv 提示protoc版本错误
    【1】EIGEN-Matrix类
    c++11的新特性
    ubuntu 16.04 python+tensorflow安装路径查看
    python的常用数据类型及其使用
    windows文件转LINUX文件格式
    ubuntu 16.04 + GPU 1080 + NVIDIA384
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/11742236.html
Copyright © 2011-2022 走看看