Mowing the Lawn【线性dp + 单调队列优化】

题目链接:https://ac.nowcoder.com/acm/contest/2652/G

题目大意:与上一篇博客 烽火传递  差不多。

1.一共n头羊,若超过m头连续的羊在一起,就会集体罢工,每头羊有一个工作效率,求如何选择羊使得工作效率最高

题解思路:

1.我们可以转换思路,首先选择全部的羊,然后这是集体罢工,我们去拆分他们,即转换成了每连续的 m + 1头羊之间必须拆掉一头羊,则作为效率损失。

2.dp[i] 表示 拆掉第 i 只羊所造成的最小总损失。于是与烽火传递一样了。

3.该题还有一个注意的点是效率是1e9范围内,我们的inf不能开0x3f3f3f3f,不够大,需开 1ll << 62。

代码如下:

 1 #include<stdio.h>
 2 #include<deque>
 3 #include<algorithm>
 4 typedef long long ll;
 5 const int MAXN = 1e5 + 100;
 6 using namespace std;
 7 const ll inf = 1ll << 62;
 8 
 9 int n, m;
10 ll a[MAXN];
11 ll dp[MAXN]; //表示第 i 个烽火台放置烽火时的最小总代价 
12 deque<int> Q;
13 
14 int main()
15 {
16     ll sum = 0;
17     scanf("%d%d",&n, &m);
18     m ++;
19     for(int i = 1; i <= n; i ++)
20     {
21         scanf("%lld", &a[i]);
22         sum += a[i];
23     }
24     for(int i = 1; i <= m; i ++)
25     {
26         dp[i] = a[i];
27         while(!Q.empty())
28         {
29             if(dp[i] < dp[Q.back()])
30                 Q.pop_back();
31             else
32                 break;
33         }
34         Q.push_back(i);
35     }
36     for(int i = m + 1; i <= n; i ++)
37     {
38         while(!Q.empty())
39         {
40             if(i - m > Q.front())
41                 Q.pop_front();
42             else
43                 break;
44         }
45         dp[i] = dp[Q.front()] + a[i];
46         while(!Q.empty())
47         {
48             if(dp[i] < dp[Q.back()])
49                 Q.pop_back();
50             else
51                 break;
52         }
53         Q.push_back(i);
54     }
55     
56     ll minn = inf;
57     for(int i = n; i > n - m; i --)
58         minn = min(minn, dp[i]);
59     printf("%lld\n", sum - minn);
60     return 0;
61 }
62 /*
63 5 3
64 1 2 5 6 2
65 
66 4
67 */ 
View Code

 

posted @ 2019-11-25 22:27  缘未到  阅读(251)  评论(0编辑  收藏  举报