U567760 序列和 题解

题解

传送门

20pts

暴力 dfs,判断是否是严格上升子序列,最后求最大值。
dfs 过程中可以记录上一项以及当前的序列和,方便剪枝和求和。
时间复杂度 O ⁡ ( 2 n ) \operatorname{O}(2^n) O(2n)

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x = 0,p = 1;
	char c = getchar();
	while(c > '9' || c < '0')	p = c == '-' ? -1 : 1,c = getchar();
	while(c >= '0' && c <= '9')	x = (x << 1) + (x << 3) + (c ^ 48),c = getchar();
	return p * x;
}
template<typename _Tp> inline void _write(_Tp x) { if(x > 9) _write(x / 10); putchar(x % 10 | 48); }
template<typename _Tp> inline void write(_Tp x) { if(x < 0) putchar('-'),x = -x; _write(x); }
template<typename _Tp> inline void writeln(_Tp x) { write(x); puts(""); }
const int N = 1e5 + 10;
int n,a[N],ans = 0;
void dfs(int step,int last = 0,int sum = 0)
{
    if(step == n + 1)
    {
        ans = max(ans,sum);
        return;
    }
    dfs(step + 1,last,sum);
    if(a[step] > last)  dfs(step + 1,a[step],sum + a[step]);
}
signed main()
{
	n = read();
	for(int i = 1;i <= n;i++)	a[i] = read();
    dfs(1);
    writeln(ans);
	return 0;
}

40pts

考虑 dp。设 f i f_i fi 为最后一项是 a i a_i ai 时的最优情况。
可以得到状态转移方程: f i = max ⁡ j = 1 i − 1 f j × [ a j < a i ] + a i f_i=\max_{j=1}^{i-1}{f_j \times [a_j < a_i]}+a_i fi=maxj=1i1fj×[aj<ai]+ai
其中当 a j < a i a_j<a_i aj<ai [ a j < a i ] [a_j<a_i] [aj<ai] 1 1 1,否则值为 0 0 0
最初 f 1 = a 1 f_1=a_1 f1=a1,最终答案为 max ⁡ i = 1 n f i \max_{i=1}^nf_i maxi=1nfi
时间复杂度 O ⁡ ( n 2 ) \operatorname{O}(n^2) O(n2)

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int x = 0,p = 1;
	char c = getchar();
	while(c > '9' || c < '0')	p = c == '-' ? -1 : 1,c = getchar();
	while(c >= '0' && c <= '9')	x = (x << 1) + (x << 3) + (c ^ 48),c = getchar();
	return p * x;
}
template<typename _Tp> inline void _write(_Tp x) { if(x > 9) _write(x / 10); putchar(x % 10 | 48); }
template<typename _Tp> inline void write(_Tp x) { if(x < 0) putchar('-'),x = -x; _write(x); }
template<typename _Tp> inline void writeln(_Tp x) { write(x); puts(""); }
const int N = 1e5 + 10;
int n,a[N],f[N];
signed main()
{
	n = read();
	for(int i = 1;i <= n;i++)	a[i] = read();
    f[1] = a[1];
    for(int i = 2;i <= n;i++)
        for(int j = 1;j < i;j++)
            if(a[j] < a[i])
                f[i] = max(f[i],f[j] + a[i]);
    writeln(*max_element(f + 1,f + n + 1));
	return 0;
}

70pts

换一种 dp 方式,设 f i , j f_{i,j} fi,j 为在前 i i i 个数中,以 j j j 结尾的子序列的最值,其中 j ≤ 1 0 3 j \le 10^3 j103
所以 f i , j = max ⁡ k = 1 i − 1 max ⁡ l = 1 j − 1 f k , l + a i f_{i,j} = \max_{k=1}^{i-1}\max_{l=1}^{j-1}f_{k,l}+a_i fi,j=maxk=1i1maxl=1j1fk,l+ai
答案为 max ⁡ i = 1 n max ⁡ j = 1 m f i , j \max_{i=1}^n\max_{j=1}^mf_{i,j} maxi=1nmaxj=1mfi,j
暴力 dp 时间复杂度为 O ⁡ ( m n ) \operatorname{O}(mn) O(mn),其中 m m m a i a_i ai 的值域。但是此时空间复杂度太高,于是需要降维。

降维后可以发现转移方程变为 f j = max ⁡ k = 1 j − 1 f k + j f_j = \max_{k=1}^{j-1}f_k+j fj=maxk=1j1fk+j
其中求 max ⁡ k = 1 j − 1 \max_{k=1}^{j-1} maxk=1j1 时可以使用树状数组将时间复杂度降至 O ⁡ ( log ⁡ m ) \operatorname{O}(\log m) O(logm),空间复杂度 O ⁡ ( m ) \operatorname{O}(m) O(m)
总时间复杂度 O ⁡ ( n log ⁡ m ) \operatorname{O}(n \log m) O(nlogm)

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int read()
{
	int x = 0,p = 1;
	char c = getchar();
	while(c > '9' || c < '0')	p = c == '-' ? -1 : 1,c = getchar();
	while(c >= '0' && c <= '9')	x = (x << 1) + (x << 3) + (c ^ 48),c = getchar();
	return p * x;
}
void _write(int x) { if(x > 9) _write(x / 10); putchar(x % 10 | 48); }
void write(int x) { if(x < 0) putchar('-'),x = -x; _write(x); }
void writeln(int x) { write(x); puts(""); }
const int N = 1e5 + 10;
int n,a[N];
int bit[1010];
struct BIT
{
    int N;
    BIT() : N(1000) {}
	int f(int x) { return x & -x; }
	void add(int x,int k)
	{
		while(x <= N)
		{
			bit[x] = max(bit[x],k);
			x += f(x);
		}
	}
	int _max(int n)
	{
		int res = 0;
		while(n >= 1)
		{
			res = max(res,bit[n]);
			n -= f(n);
		}
		return res;
	}
};
signed main()
{
	n = read();
	for(int i = 1;i <= n;i++)	a[i] = read();
	BIT _bit;
	for(int i = 1;i <= n;i++)
	{
		_bit.add(a[i],a[i] + _bit._max(a[i] - 1));
	}
	cout << _bit._max(1000) << endl; 
	return 0;
}

100pts

在 70pts 的基础上进行离散化。
时间复杂度 O ⁡ ( n log ⁡ n ) \operatorname{O}(n \log n) O(nlogn)
空间复杂度 O ⁡ ( n ) \operatorname{O}(n) O(n)

AC Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int read()
{
	int x = 0,p = 1;
	char c = getchar();
	while(c > '9' || c < '0')	p = c == '-' ? -1 : 1,c = getchar();
	while(c >= '0' && c <= '9')	x = (x << 1) + (x << 3) + (c ^ 48),c = getchar();
	return p * x;
}
void _write(int x) { if(x > 9) _write(x / 10); putchar(x % 10 | 48); }
void write(int x) { if(x < 0) putchar('-'),x = -x; _write(x); }
void writeln(int x) { write(x); puts(""); }
const int N = 1e5 + 10;
int n,a[N],b[N];
map<int,int> rk;
int bit[N];
struct BIT
{
	int f(int x) { return x & -x; }
	void add(int x,int k)
	{
		while(x <= n)
		{
			bit[x] = max(bit[x],k);
			x += f(x);
		}
	}
	int _max(int n)
	{
		int res = 0;
		while(n >= 1)
		{
			res = max(res,bit[n]);
			n -= f(n);
		}
		return res;
	}
};
signed main()
{
	n = read();
	for(int i = 1;i <= n;i++)	b[i] = a[i] = read();
	sort(b + 1,b + n + 1);
	for(int i = 1;i <= n;i++)	rk[b[i]] = i;
	BIT _bit;
	for(int i = 1;i <= n;i++)
	{
		_bit.add(rk[a[i]],a[i] + _bit._max(rk[a[i]] - 1));
	}
	cout << _bit._max(n) << endl; 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿Eason

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值