拿数问题 II(动态规划)

问题描述

YJQ 上完第10周的程序设计思维与实践后,想到一个绝妙的主意,他对拿数问题做了一点小修改,使得这道题变成了 拿数问题 II。

给一个序列,里边有 n 个数,每一步能拿走一个数,比如拿第 i 个数, Ai = x,得到相应的分数 x,但拿掉这个 Ai 后,x+1 和 x-1 (如果有 Aj = x+1 或 Aj = x-1 存在) 就会变得不可拿(但是有 Aj = x 的话可以继续拿这个 x)。求最大分数。

Input

第一行包含一个整数 n (1 ≤ n ≤ 105),表示数字里的元素的个数

第二行包含n个整数a1, a2, …, an (1 ≤ ai ≤ 105)

Output

输出一个整数:n你能得到最大分值。

Sample input & ouput

Sample input1
2
1 2
Sample output1
2
Sample input2
3
1 2 3
Sample output2
4
Sample input3
9 
1 2 1 3 2 2 2 2 3
Sample output3
10

Hint

对于第三个样例:先选任何一个值为2的元素,最后数组内剩下4个2。然后4次选择2,最终得到10分。

解题思路

这个题和一般的取数问题的区别在于它是取的数加减1不能选,而一般的问题是下标加减1不能选,因此我们可以想到将此题转化为一般的取数问题,也就是将数x,放到a[x]中,这样x选择后,x-1和x+1不能选就变成了a[x]选择后,a[x-1]和a[x+1]不能选。然后按照一般的取数问题来做就行了。

状态转移方程还是dp[i]=max(dp[i-1],dp[i-2]+a[i]),也就是当前点为止的结果是没有取这个数的dp[i-1]和取了这个数,没有取上一个数的dp[i-2]+a[i]的最大值。最终输出dp[maxx]即可。(maxx是输入数据中的最大值)

完整代码

//#pragma GCC optimize(2)
//#pragma G++ optimize(2)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int maxn=100000+10;
long long n,a[maxn],dp[maxn],len;
long long getint(){
    long long x=0,s=1; char ch=' ';
    while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
    return x*s;
}
int main(){
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    n=getint();
    for (long long i=1; i<=n; i++){
        long long temp=getint();
        a[temp]+=temp;
        len=max(len,temp);
    }
    dp[1]=a[1];
    for (long long i=2; i<=len; i++)
        dp[i]=max(dp[i-1],dp[i-2]+a[i]);
    printf("%lld\n",dp[len]);
    return 0;
}
原创文章 61 获赞 58 访问量 6479

猜你喜欢

转载自blog.csdn.net/weixin_43347376/article/details/105739945