YTU 4260 cv工程师的小礼物

题目描述

cv工程师现在送你一个数组作为蓝桥杯结束的礼物,你可以从这个数组中选择任意多个不相邻的数字,请最大化你选择的数字之和。

数据范围:1≤n≤200000,−10^9≤ai≤10^9。

输入

第一行:一个数字 n 代表数组大小。

第二行:n 个数字,保证是整数(存在负数)。

输出

一个整数,表示你选择的数字之和。

输入输出样例

样例输入 #1

复制

4
2 1 1 1
样例输出 #1

复制

3

提示

小朋友,贪心不对哟

思路讲解:

这道题考察动态规划,首先我们要明白状态是什么,状态dp[i]表示以数字i作为最后一个数字的最大数字和,那么因为这道题要选择不相邻的数字,我们再来看状态转移,不相邻的数字也就意味着如果选择了第a[i]个数,第a[i-1]个数字一定不能选,从第1个数字到第i-2个数字都可以转移到第i个数字

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

#define int long long

const int N=200010;

int a[N];

int dp[N];

int maxsum;

signed main()
{
    int n; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        dp[i]=a[i];
        for(int j=1;j<=i-2;j++)
        {
            dp[i]=max(dp[i],dp[j]+a[i]);
        }
        maxsum=max(maxsum,dp[i]);
    }
    cout<<maxsum<<endl;
    return 0;
}

那么代码将会这么写,但你会发现TLE了,因为这道题n的数据范围非常的大,然后这个代码是n 方的时间复杂度,所以时间超限了。

优化:

(建议同学们可以先做一下问题 3144: 动态规划进阶题目之大盗阿福)

那么我们如何在O(n)的时间复杂度内解决这道题呢,
我们看,如果n为1的话,dp[1]=a[1];

n=2的哈,dp[2]=max(a[1],a[2]);
然后从3开始往后,他可能从前一个数直接转移过来,也可以从第i-2个数转移过来,dp[i-2]+a[i]
 

这道题有两个易错点:
1.这道题目的数字并非全部都是正数,也有负数,所以并不是选的数字越多越好,比如dp[3]的话,并不是选数字1和3 的和就比数字3要大,所以dp[3]更新的时候还要和a[3]做一下比较。
2.这道题目题干说的是选择任意多个不相邻的数字,这个任意多个就包括0个,也就是说,如果这些数字全是负数的话,你选数会越选越小,这时,你不如选择0个数字,这样的话,最大的和就是0了。

 OK,上正确代码
 

AC代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

#define int long long

const int N=200010;

int a[N];

int dp[N];

signed main()
{
    int n; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    dp[1]=a[1];
    dp[2]=max(a[1],a[2]);
    for(int i=3;i<=n;i++)
    {
        dp[i]=max(a[i],max(dp[i-1],dp[i-2]+a[i]));
    }
    cout<<max((ll)0,dp[n])<<endl;
    return 0;
}


 

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值