常州大学新生寒假训练会试 D 训练技巧

 1 // 常州大学新生寒假训练会试  D     训练技巧
 2 /*
 3 常州大学组织了新生寒假训练一共N天,每天训练可以获得的训练效果是Ei。但是如果连续训练超过K天,萌新们会受不了而被劝退。
 4 现在负责人想知道,如何安排能保证萌新不会被劝退并且能获得最大的训练效果。
 5 输入描述:
 6 第一行:两个用空格隔开的整数:N和K,1≤N≤100000,1≤K≤N
 7 第二行到N+1行:第i+1行有一个整数,表示第N天的训练效果是Ei,(0 <= Ei <= 1,000,000,000)
 8 输出描述:
 9 第一行:单个整数,表示最大的能力之和
10 */
11 //dp+单调队列
12 #include <iostream>
13 #include <cstdio>
14 #include <cstring>
15 #include <string>
16 #include <algorithm>
17 #include <utility>
18 #include <vector>
19 #include <map>
20 #include <queue>
21 #include <stack>
22 #include <cstdlib>
23 #include <deque>
24 typedef long long ll;
25 #define lowbit(x) (x&(-x))
26 #define ls l,m,rt<<1
27 #define rs m+1,r,rt<<1|1
28 using namespace std;
29 int n,k;
30 const int N=1e5+9;
31 ll dp[N],e[N];
32 int main ()
33 {
34     scanf("%d%d",&n,&k);
35     ll sum=0;
36     for(int i=1;i<=n;i++){
37         scanf("%lld",&e[i]);
38         sum+=e[i];
39     }
40     e[0]=0;
41     dp[0]=e[0];
42     deque<ll>q;
43     //队首和队尾都可以插入和弹出
44     q.push_front(e[0]);
45     //dp[i] : 到第i个数为止不取第i个数的最小损失
46     //只能保证前面的是满足题意的
47     //q.front 是最小的,back 是最大的
48     for(int  i=1;i<=n;i++)
49     {
50         dp[i]=dp[q.front()]+e[i];
51         while(!q.empty()&&dp[q.back()]>=dp[i]){
52             q.pop_back();//把后面的大于dp[i]的弹出
53             //为了加入i后,dp[i]是最大的
54         }
55         q.push_back(i);
56         while(!q.empty()&&q.front()<i-k){
57             q.pop_front();//为了下一个满足不可连取超过K
58         }
59         /*
60         1 2 3 4 5
61         例如 :i==4,那么j 最小为1,即j>=i-k-1
62         也就是说 j<i-k-1时应弹出
63         但这是针对i 的,那么针对i+1的话即使
64         j<i-k(有加有减)
65         */
66     }
67     ll ans=0;
68     // 要前后都满足条件,就要从n-k到n遍历
69     for(int i=n-k;i<=n;i++){
70         ans=max(ans,sum-dp[i]);
71     }
72     // sum-最小的==剩下的最大的
73     printf("%lld\n",ans);
74     return      0;
75 } 

猜你喜欢

转载自www.cnblogs.com/tingtin/p/9317936.html
今日推荐