BZOJ 2442 [Usaco2011 Open]修剪草坪:單調佇列優化dp

Leohh發表於2017-10-09

題目連結: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 }

 

相關文章