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 }

 

posted @ 2017-10-09 18:33  Leohh  阅读(176)  评论(0编辑  收藏  举报