zoukankan      html  css  js  c++  java
  • BZOJ 2442 [Usaco2011 Open]修剪草坪:单调队列优化dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2442

    题意:

      有n个数a[i]从左到右排成一排。

      你可以任意选数,但是连续的数不能超过k个。

      问你最大的选数之和。

    题解:

      表示状态:

        dp[i]表示考虑了第i个数的最大之和。

      

      找出答案:

        ans = dp[n]

        将所有的数都考虑过了

      如何转移:

        对于a[i],要么选,要么不选。

        (1)如果不选,则dp[i] = max dp[i-1]。

        (2)如果选,则最多往前选k个数,且在i-k的位置一定不能选。

          所以:

            dp[i] = max dp[j] + sum(j+2,i) (i-k-1 <= j <= i-2)

          变成前缀和的形式:

            dp[i] = max dp[j] + sum[i] - sum[j+1]

          也就是:

            dp[i] = max(dp[j] - sum[j+1]) + sum[i]

          对于dp[j] - sum[j+1]这一部分,可以用单调队列优化。

      边界条件:

        dp[0] = 0

        q[head++] = Node(-1,0)

        -1为假想的位置,只是为了在n == 1的时候能够用到0这个值。

    AC Code:

     1 // state expression:
     2 // dp[i] = max efficiency
     3 // i: selected ith cow
     4 //
     5 // find the answer:
     6 // max dp[n]
     7 //
     8 // transferring:
     9 // dp[i] = max(dp[j] + sum(j+2,i), dp[i-1])
    10 // dp[i] = max(dp[j] + sum[i] - sum[j+1], dp[i-1])
    11 // dp[i] = max(dp[j] - sum[j+1] + sum[i], dp[i-1])
    12 // i-k-1 <= j <= i-2
    13 //
    14 // boundary:
    15 // dp[0] = 0
    16 #include <iostream>
    17 #include <stdio.h>
    18 #include <string.h>
    19 #define MAX_N 100005
    20 
    21 using namespace std;
    22 
    23 struct Node
    24 {
    25     int idx;
    26     long long val;
    27     Node(int _idx,long long _val)
    28     {
    29         idx=_idx;
    30         val=_val;
    31     }
    32     Node(){}
    33 };
    34 
    35 int n,k;
    36 int head=0;
    37 int tail=0;
    38 int e[MAX_N];
    39 long long dp[MAX_N];
    40 long long sum[MAX_N];
    41 Node q[MAX_N];
    42 
    43 void read()
    44 {
    45     cin>>n>>k;
    46     sum[0]=0;
    47     for(int i=1;i<=n;i++)
    48     {
    49         cin>>e[i];
    50         sum[i]=sum[i-1]+e[i];
    51     }
    52 }
    53 
    54 void solve()
    55 {
    56     dp[0]=0;
    57     q[tail++]=Node(-1,0);
    58     for(int i=1;i<=n;i++)
    59     {
    60         if(i>=2)
    61         {
    62             while(head<tail && q[tail-1].val<dp[i-2]-sum[i-1]) tail--;
    63             q[tail++]=Node(i-2,dp[i-2]-sum[i-1]);
    64         }
    65         while(head<tail && q[head].idx<i-k-1) head++;
    66         dp[i]=max(q[head].val+sum[i],dp[i-1]);
    67     }
    68 }
    69 
    70 void print()
    71 {
    72     cout<<dp[n]<<endl;
    73 }
    74 
    75 int main()
    76 {
    77     read();
    78     solve();
    79     print();
    80 }
  • 相关阅读:
    rsync服务器与客户端配置文件
    0170001799 SQL Parsing Messages .
    RHEL修改最大文件打开数,关于epoll socket Too many open files问题的解决
    精美网页集锦
    Linux 相关发音
    【转】如何提升工作中的影响力
    2010年50大最佳工作场所 谷歌仅排名第14
    加密解密工具gpg (GnuPG)
    【转】易经与软件开发
    常见的开放源代码许可证类型
  • 原文地址:https://www.cnblogs.com/Leohh/p/7642441.html
Copyright © 2011-2022 走看看