前缀和+后缀最大值(dp)

题目描述:

今天qwb要参加一个数学考试,这套试卷一共有n道题,每道题qwb能获得的分数为ai,qwb并不打算把这些题全做完,
他想选总共2k道题来做,并且期望他能获得的分数尽可能的大,他准备选2个不连续的长度为k的区间,
即[L,L+1,L+2,....,L+k-1],[R,R+1,R+2,...,R+k-1](R >= L+k)。

思路:

先用前缀和进行预处理

再维护一个dp数组,dp[i]表示,i 到 n中长度为k的区间的和的最大值

然后就可以枚举第一个区间,通过O(1)的复杂度得到第二区间的最大值

坑点

要开longlong

数组要开够

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 300000 + 50
#define endl '\n'
#define seed 13331
#define mod 1000000007
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define mem(a,b) memset((a),(b),sizeof(a))
typedef  long long ll ;

inline ll llRead(){ll x(0), t(1);char o (getchar());while (o < '0' || o > '9') {if (o == '-') {t = -1;}o = getchar();}for (; o >= '0' && o <= '9'; o = getchar()) {x = (x << 1) + (x << 3) + (o ^ 48);}return x * t;}



ll t;
ll n, k;
ll tr[MAX];
ll sum[MAX];
ll dp[MAX];

void init(){
    mem(tr, 0);
    mem(dp, 0);
    mem(sum, 0);
}

int main(){
    t = llRead();
    while (t--) {
        init();
        n = llRead();k = llRead();
        for(int i = 1; i <= n; ++i)tr[i] = llRead();
        for(int i = 1; i <= n; ++i)sum[i] = sum[i - 1] + tr[i];
        ll ma = -1e18;
        for(ll i = n; i >= k; --i){
            ma = max(ma, sum[i] - sum[i - k]);
            dp[i] = ma;
        }
        ma = -1e18;
        for(ll i = k; i <= n - k; ++i){
            ma = max(ma, sum[i] - sum[i - k] + dp[i + k]);
        }
        cout<<ma<<endl;
    }
    return 0;
}
动态规划 文章被收录于专栏

dp的专项训练

全部评论

相关推荐

不愿透露姓名的神秘牛友
11-21 19:05
面试官_我太想进步了:混学生会的,难怪简历这么水
点赞 评论 收藏
分享
点赞 评论 收藏
分享
10-15 10:57
已编辑
武昌理工学院 FPGA工程师
狠赚笔第一人:老哥学院本没实习还想拿13k学Java狠赚笔呢
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务