【最大上升子序列和】

题目

在这里插入图片描述


前置芝士

1. erase 函数
erase(iterator pos):删除单个元素,其中 pos 是要删除元素的迭代器。
erase(iterator first, iterator last):删除从 first 到 last(不包括 last)之间的所有元素。

2. unique 函数
unique 函数用于去除容器中相邻的重复元素,并返回一个迭代器,指向去重后容器中最后一个有效元素的下一个位置。
unique(iterator first, iterator last):处理从 first 到 last(不包括 last)之间的元素。
3. lower_bound 函数
lower_bound(iterator first, iterator last, const T& value):在从 first 到 last(不包括 last)之间的元素中查找第一个大于等于 value 的元素的位置,返回对应迭代器it,如果不存在则返回.end()


思路

如果数据足够小,可以采用二重循环+dp

状态定义:
f [ i ] 对应 1 到 i 号元素形成的序列中,包括第 i 个元素的所有上升子序列的集合 f[i]对应1到i号元素形成的序列中,包括第i个元素的所有上升子序列的集合 f[i]对应1i号元素形成的序列中,包括第i个元素的所有上升子序列的集合
f [ i ] 表示和的最大值 f[i]表示和的最大值 f[i]表示和的最大值

状态转移:
f [ j ] = m a x    1 < = i < j = n , a [ i ] < a [ j ] ( f [ i ] ) + a [ j ] f[j] = max_{\;1<=i<j=n, a[i] < a[j]}(f[i]) + a[j] f[j]=max1<=i<j=n,a[i]<a[j](f[i])+a[j]

目标状态:
m a x    1 < = i < = n ( f [ i ] ) max_{\;1<=i<=n}(f[i]) max1<=i<=n(f[i])

树状数组优化状态转移:
从求前缀和转求前缀最大值
m a x    1 < = i < j = n , a [ i ] < a [ j ] ( f [ i ] ) = q u e r y ( x − 1 ) ,    m a p p i n g ( a [ i ] ) = x max_{\;1<=i<j=n, a[i] < a[j]}(f[i]) = query(x-1), \;mapping(a[i]) = x max1<=i<j=n,a[i]<a[j](f[i])=query(x1),mapping(a[i])=x

数组下标表示数值大小 不可以, a [ i ] ∈ [ 1 , 1 0 9 ] a[i]\in[1,10^{9}] a[i][1,109]

离散化:从存储值域转为存储实际存在的值,数的大小关系仍由下标体现,但范围不再离散且那么大,转而连续且取决于数的个数
步骤

  1. 排序 sort(g.begin(), g.end());
  2. 去重 g.erase(unique(g.begin(), g.end()), g.end());
  3. 映射函数mapping(将原始下标映射为离散化存储后的下标) int x = lower_bound(g.begin(), g.end(), a[i]) - g.begin() + 1;

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
vector<int> g;
int a[N];
LL tr[N], f[N];
int n, m;
int lowbit(int x)
{
    return x & -x;
}
void add(int x, LL d)
{
    for(; x <= m; x += lowbit(x)) tr[x] = max(tr[x], d);
}
LL query(int x)
{
    LL retval = 0;
    for(; x; x -= lowbit(x)) retval = max(retval, tr[x]);
    return retval;
}
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i], g.push_back(a[i]);
    
    sort(g.begin(), g.end());
    g.erase(unique(g.begin(), g.end()), g.end());
    m = g.size();
    
    for(int i = 1; i <= n; i++)
    {
        int x = lower_bound(g.begin(), g.end(), a[i]) - g.begin() + 1;
        f[i] = query(x-1) + a[i];
        add(x, f[i]);
    }
    
    LL res = 0;
    for(int i = 1; i <= n; i++) res = max(res, f[i]);
    cout << res;
    
    return 0;
    
}
  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值