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 */