P2642 双子序列最大和(线性DP)(最大子段和 + 合唱队列)

P2642 双子序列最大和

在这里插入图片描述
首先考虑单个的最大子序列和

	f[i] = max(f[i - 1] + a,a);
	ans = max(ans,f[i]);

这里的预处理方法类似合唱队列我们处理pre和nex两个数组,分别表示以i为结尾1~i的最大子序列和,以及以i为起点的i~n的最大子序列和,我们枚举中间点,答案就是

    ll ans = pre[1] + nex[3];
    for(int i = 3; i < n; ++ i){//题目要求至少隔一个数
        ans = max(ans, pre[i - 1] + nex[i + 1]);
    }

注意我们要先给ans赋值为 pre[1] + nex[3],不能写成0,因为我们这里for循环的时候不能取到n,因为n+1,但是如果n == 3,那么我们这里for循环是不会进去的,会直接跳出,ans这时候就会变成0而不是正确答案pre[1] + nex[3]

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>

using namespace std;
//typedef unsigned long long ll;
typedef long long ll;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 1000007, M = 5000007;
const ll INF = 1e14;

inline void read(int &x)
{
	char c = getchar();
	while ((c < 48) || (c > 57)) c = getchar();
	x = c ^ 48;c = getchar();
	while ((c >= 48) && (c <= 57))
	{
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
}

int n, m;
int t;
ll tot, cnt, ans;
int arr[N];
ll a[N];
ll pre[N], nex[N];

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%lld", &a[i]);
    }
    pre[1] = a[1];
    for(int i = 2; i <= n; ++ i)
        pre[i] = max(pre[i - 1] + a[i], a[i]);
    for(int i = 2; i <= n; ++ i)
        pre[i] = max(pre[i - 1], pre[i]);
    nex[n] = a[n];
    for(int i = n - 1; i >= 1; -- i)
        nex[i] = max(nex[i + 1] + a[i], a[i]);
    for(int i = n - 1; i >= 1; -- i)
        nex[i] = max(nex[i + 1], nex[i]);
        
    ll ans = pre[1] + nex[3];
    for(int i = 3; i < n; ++ i){//题目要求至少隔一个数
        ans = max(ans, pre[i - 1] + nex[i + 1]);
    }

    printf("%lld\n" ,ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45697774/article/details/108474749