题解:最大上升子序列和

本文介绍了如何运用树状数组优化算法解决最大上升子序列和的问题。通过状态表示f[i]表示以a[i]为结尾的最大上升子序列的和,以及利用二分查找和树状数组实现O(n log n)的时间复杂度,从而避免了暴力求解导致的超时。代码示例中详细展示了算法实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最大上升子序列和

给定一个长度为 n 的整数序列 a1,a2,…,an。

请你选出一个该序列的严格上升子序列,要求所选子序列的各元素之和尽可能大。

请问这个最大值是多少?

输入格式
第一行包含整数 n。

第二行包含 n 个整数 a1,a2,…,an。

输出格式
输出最大的上升子序列和。

数据范围
对于前三个测试点,1≤n≤4。
对于全部测试点,1≤n≤105,1≤ai≤109。

输入样例1:
2
100 40
输出样例1:
100
输入样例2:
4
1 9 7 10
输出样例2:
20
样例解释
对于样例 1,我们只选取 100。

对于样例 2,我们选取 1,9,10。

题解

最长上升子序列的一样的思路。
状态表示
f[i]表示 以a[i]为结尾的最大上升子序列的和。
状态划分
以倒数第二个数字划分
则可以为没有,a[0],a[1],…,a[i-1]

f[i] = max(f[j] + a[i], f[i]) 0<=j < i, a[j] < a[i]

但n = 1e5,O(n2)O(n^2)O(n2)复杂度会超时。采用树状数组或者线段树优化,维护f[i]的最大值,快速求f[0~i-1]的最大值。

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long LL;
vector<int>xs;
int n, a[N];
LL f[N], tr[N];
int get(int x){
    return lower_bound(xs.begin(), xs.end(), x) - xs.begin() + 1;
}
void add(int x, LL val){
    while(x <= n){
        tr[x] =max(val, tr[x]);
        x += x&(-x);
    }
}
LL query(int x){
    LL res = 0;
    while(x){
        res = max(tr[x], res);
        x -= x&(-x);
    }
    return res;
}
int main(){
    
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        xs.push_back(a[i]);
    }
    sort(xs.begin(), xs.end());
    xs.erase(unique(xs.begin(), xs.end()), xs.end());
    
    LL ans = 0;
    for(int i = 1; i <= n; i++){
        int pos = get(a[i]);
        f[i] = a[i] + query(pos - 1);
        ans = max(f[i], ans);
        add(pos, f[i]);
    }
    printf("%lld", ans);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值