F

题目大意:从n个数里边选n/2个数,问和最大是多少。

题解:这是一个比较有意思的DP,定义状态dp[i][1],表示选了第i个数的最优状态,dp[i][0]表示没有选第i个数的最优状态。

状态是如何转移的呢?

1  2  3  4  5  6  7....

假设考虑到第7个数,前7个数我们要选7/2=3个数。

    如果我们选了第7个数那么我们 只需要从前边再选2个数,我们可以从前5个数里边选2个,也可以从前4个数里边选2个,所以dp[i][1]=max({dp[i-2][1],dp[i-2][0],dp[i-3][1],dp[i-3][0]})+arr[i]。  

    如果我们不选第7个数,那就相当于从前6个数选3个喽,直接继承i-1就可以了。dp[i][0]=max(dp[i-1][0],dp[i-1][1])

假设我们考虑到第6个数,前6个数我们要选3个。

    如果第6个选了,那只能从前4个里边选2个了,不能在往前了,因为3/2=1了。。。所以dp[i][1]=max(dp[i-2][1],dp[i-2][0])+arr[i]。

    如果第6个不选,也就说要从前5个里边选3个了,假设第5个不选,从前4个里边选3个肯定是不满足条件的,所以第5个必须选,然后在加上第四个不选的情况,所以转移方程为dp[i][0]=arr[i-1]+dp[i-2][0]。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+7;
ll dp[N][2];
ll arr[N];
int main(){
    ll n;
    cin>>n;
    for(ll i=1;i<=n;i++)  cin>>arr[i];
    dp[2][0]=arr[1];
    dp[2][1]=arr[2];
    for(ll i=3;i<=n;i++){
        if(i&1){
            dp[i][1]=max({dp[i-2][1],dp[i-2][0],dp[i-3][1],dp[i-3][0]})+arr[i];
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
        }
        else {
            dp[i][1]=max(dp[i-2][1],dp[i-2][0])+arr[i];
            dp[i][0]=arr[i-1]+dp[i-2][0];
        }
    }
    cout<<max(dp[n][0],dp[n][1])<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Accepting/p/12698033.html