Flat Subsequence 题解

思路

一道线段树优化 dp 题。

\(dp_i\) 表示以第 \(i\) 个数字结尾的最长选数列长度,则 \(dp_i=\max(dp_i, dp_j)+1\),其中 \(j<i\)\(| a_i-a_j | \leq K\)

时间复杂度为 \(O(n^2)\)

代码如下:

int ans = 0;
rep(i, 1, n)
{
    dp[i] = 1;
    rep(j, 1, i - 1)
        if(abs(a[i] - a[j]) <= k)
            dp[i] = max(dp[i], dp[j] + 1);
    ans = max(ans, dp[i]);
}
cout << ans << endl;

但是 \(n \leq 300000\),会 TLE,考虑优化。

又可发现上述代码中:

rep(j, 1, i - 1)
    if(abs(a[i] - a[j]) <= k)
        dp[i] = max(dp[i], dp[j] + 1);

这不就是求 \(a_i-k,a_i+k\) 之间的最值呀!

可以用线段树来进行维护,最后记得修改 \(dp_i\) 的值即可。

代码如下

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define rep(i, l, r) for(int i = l; i <= r; ++ i)
#define per(i, r, l) for(int i = r; i >= l; -- i)
#define me0(a); memset(a, 0, sizeof a);
#define me3(a); memset(a, 0x3f, sizeof a);
#define PII pair<int, int>

const int INF = 0x3f3f3f3f, MOD = 1e9 + 7;

inline void read(int &n)
{
    bool w = 0;
    char c = getchar();
    for(; c < 48 || c > 57; c = getchar())
        w = c == 45;
    for(n = 0; c >= 48 && c <= 57; c = getchar())
        n = n * 10 + c - 48;
    n = w ? -n : n;
}

inline void write(int x, char a)
{
    char c[40], s = 0;
    if(x < 0) putchar(45), x = -x;
    for(; x ;) c[s ++] = x % 10, x /= 10;
    if(!s) putchar(48);
    for(; s -- ;) putchar(c[s] + 48);
    putchar(a);
}

const int MAXN = 300001, M = 300000;
#define ls num + num
#define rs num + num + 1
int sum[MAXN << 2], p[MAXN], addans = -INF;
void update(int num) {sum[num] = max(sum[ls] , sum[rs]);}
void ask(int num, int l, int r, int x, int y)
{
	if(x <= l && r <= y)
	{
		addans = max(addans, sum[num]);
		return;
	}
	int mid = (l + r) >> 1;
	if(mid >= x) ask(ls, l, mid, x, y);
	if(mid < y) ask(rs, mid + 1, r, x, y);
}
void change(int num, int l, int r, int pos, int val)
{
	if(l == r)
	{
		sum[num] = val;
		return;
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) change(ls, l, mid, pos, val);
	else change(rs, mid + 1, r, pos, val);
	update(num);
}
int n, k, ans;
int dp[MAXN];
int a[MAXN];
main()
{
    read(n); read(k);
    rep(i, 1, n) read(a[i]);
    rep(i, 1, n)
	{
		int L = max(0ll, a[i] - k), R = min(M, a[i] + k);
        ask(1, 0, M, L, R);
		dp[i] = addans + 1;
		change(1, 0, M, a[i], dp[i]);
		ans = max(ans, dp[i]);
        addans = -INF;
	}
	cout << ans;
}
posted @ 2023-07-01 10:52  liukejie  阅读(4)  评论(0编辑  收藏  举报