D 训练技巧(dp,单调队列优化)

题目链接:https://www.nowcoder.net/acm/contest/78/D

 

有n天,每天训练收益为Ei,如果连续训练了k天,则必须休息一天,问训练的最大收益,1<=n,k<=1e5

 

dp[i]表示第i天不训练,前i天的最小损失,dp[i] = min(dp[i],dp[j] - a[i])   ( j = i-1 , i-2 ,,,, i-k-1 )

答案就是第n+1天不训练,sum-前n天的最小损失喽

 

这样还是会超时,需要单调队列优化,单调队列:把队列的最值维护在队首,不考虑其它元素,队列总是单调递增或递减的,所以出队、入队操作和普通队列不一样。

 

代码:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<vector>
 6 #include<bitset>
 7 using namespace std;
 8 typedef long long ll;
 9 ll a[100005]={0},dp[100005];
10 typedef struct Node{
11     int num;
12     ll v;
13 }node;
14 node que[100005];
15 
16 int main()
17 {
18     int n,k,l=0,r=-1;
19     ll sum=0;
20     scanf("%d%d",&n,&k);
21     for(int i=1;i<=n;i++)
22         {scanf("%lld",&a[i]);sum+=a[i];}
23         
24     dp[0]=0,que[++r].v=0,que[r].num=0;
25     
26     for(int i=1;i<=n+1;i++)
27         {
28             dp[i]=que[l].v-a[i];
29             while(l<=r&&dp[i]>=que[r].v) r--;
30             que[++r].v=dp[i],que[r].num=i;
31             while(l<=r&&i-k-1>=que[l].num) l++;
32         
33         }
34     printf("%lld\n",dp[n+1]+sum);
35 }

 

posted @ 2018-02-08 23:13  hzhuan  阅读(208)  评论(0编辑  收藏  举报