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 }
常州大学新生寒假训练会试 D 训练技巧
猜你喜欢
转载自www.cnblogs.com/tingtin/p/9317936.html
今日推荐
周排行