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 }