3662. 最大上升子序列和

题目链接

3662. 最大上升子序列和

给定一个长度为 \(n\) 的整数序列 \(a_1,a_2,…,a_n\)

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

请问这个最大值是多少?

输入格式

第一行包含整数 \(n\)

第二行包含 \(n\) 个整数 \(a_1,a_2,…,a_n\)

输出格式

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

数据范围

对于前三个测试点,\(1≤n≤4\)
对于全部测试点,\(1≤n≤10^5,1≤a_i≤10^9\)

输入样例1:

2
100 40

输出样例1:

100

输入样例2:

4
1 9 7 10

输出样例2:

20

样例解释

对于样例 \(1\),我们只选取 \(100\)

对于样例 \(2\),我们选取 \(1,9,10\)

解题思路

树状数组,dp

  • 状态表示:\(f[i]\) 为以 \(i\) 结尾的最大子序列和

  • 状态计算:\(f[i]=max(f[i],f[j]+a[i])\),其中 \(a[i]>a[j]\)

考虑优化,其中关键在于找出满足 \(a[i]>a[j]\)\(f[j]\) 的最大值,可以用树状数组处理,这里树状数组用来处理当前小于 \(a[i]\) 的最大的 \(f[j]\),同时由于值过大可离散化

  • 时间复杂度:\(O(nlogn)\)

代码

// Problem: 最大上升子序列和
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/3665/
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
int n,a[N];
LL f[N],tr[N];
vector<int> v;
int find(int x)
{
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void add(int x,LL y)
{
	for(;x<=v.size();x+=x&-x)tr[x]=max(tr[x],y);
}
LL ask(int x)
{
	LL res=0;
	for(;x;x-=x&-x)res=max(res,tr[x]);
	return res;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	v.pb(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
	for(int i=1;i<=n;i++)
	{
		f[i]=max(f[i],1ll*a[i]+ask(find(a[i])-1));
		add(find(a[i]),f[i]);
	}
	cout<<*max_element(f+1,f+1+n);
    return 0;
}
posted @ 2022-03-01 21:38  zyy2001  阅读(29)  评论(0编辑  收藏  举报