题解 | #数学考试#

数学考试

https://ac.nowcoder.com/acm/problem/15553

链接:https://ac.nowcoder.com/acm/contest/24213/1013
来源:牛客网

题目描述

今天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)。

输入描述:

第一行一个整数T(T<=10),代表有T组数据
接下来一行两个整数n,k,(2<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,...,an,(-100,000<=ai<=100,000)

输出描述:

输出一个整数,qwb能获得的最大分数

题型:

动态规划--求2个没有交集的长度固定的区间的最大值总和

思路:

1.明确原问题:2个没有交集的长度为k的区间的最大值总和
2.明确子问题:求出1个长度为k的区间的最大值-->如何求出数组上某个长度为k的区间的值-->考虑用前缀和sum[]来求,即dp[i]=sum[i]-sum[i-k]
3.明确状态转移方程:dp[i]=max(dp[i-1],sum[i]-sum[i-k])(注意:i>=k),这个方程能够求出1个长度为k的区间的最大值
4.转化成求2个长度为k的区间的最大值,即可以开两个dp[]数组,一个记录从左边开始的长度为k的区间的最大值,即dp[i]=max(dp[i-1],sum[i]-sum[i-k])(注意:i>=k && i<=n-k(<=n-k是为了防止其与最右边的区间有交集),另一个记录从右边开始的长度为k的区间的最大值,即dp[i]=max(dp[i+1],sum[i+k-1]-sum[i-1])(注意:i>=k+1 && i<=n-k+1(>=k+1是为了防止其与最左边的区间有交集)
5.最后求两个区间的最大值总和,即ans=max(ans,dp左[i]+dp右[i]);(i>=k && i<=n-k)

代码:

#include<bits/stdc++.h>
#define ll long long int
using namespace std;
ll a[200200],sum[200200],dpl[200200],dpr[200200],ans;
int main(){
    int T,n,k;
    scanf("%d",&T);
    while(T--){
        ans=-9999999999999999;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1;i<=n;i++){
            dpl[i]=-9999999999999999;
            dpr[i]=-9999999999999999;
        }
        for(int i=n-k+1;i>=k+1;i--){
            dpr[i]=max(dpr[i+1],sum[i+k-1]-sum[i-1]);
        }
        for(int i=k;i<=n-k;i++){
            dpl[i]=max(dpl[i-1],sum[i]-sum[i-k]);
            ans=max(ans,dpl[i]+dpr[i+1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

这是本人对于算法入门班共十三章习题的题解与个人的一些感悟,本人写题解的目的是对于某些经典的/陌生的/无从下手的/思维方向错误的题目加深印象。 希望自己能够在学习算法的路上走得更远,今天也是努力学习的一天!

全部评论

相关推荐

AAA专业长城贴瓷砖刘大爷:这样的简历我会直接丢进垃圾桶,花里胡哨的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务