CF977F Consecutive Subsequence 题解

CF977F Consecutive Subsequence 题解

原题链接

洛谷
CF

题目大意

给定一个长度为 \(n\) 的数列 \(A\), 求 \(A\) 中最长连续上升子序列的长度并输出任意一种最长的序列中每个数在 \(A\) 中的位置.

思路

求长度应该比较好求, 我们可以设 \(d[i]\) 为 从 \(Ai\) 开始的子序列的最长长度, 显然有 \(d[Ai] = d[Ai+1] + 1\). 那么最长长度(假设她叫 \(ans\))即为 \(max(\forall d[Ai])\), 而输出位置的话我们只需要在计算\(ans\)时顺便看这个序列的第一个节点是什么(假如他是 st), 然后在 \(A\) 中从左到右依次寻找 \(st\), \(st+1\), ..., \(st+ans\) 的位置即可.

发现 \(Ai <= 1e9\), 就必须离散化.

如果用普通的离散话会 WA(我一开始就是这样的), 代码如下( \(ma\) 是用来离散化的):

#include <stdio.h>
#include <algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))

struct NODE {
	int oldnum;
	int oldid;
	int truerank;
	const inline bool operator < (const NODE &rhs) const {
		return oldnum < rhs.oldnum;
	}
} ma[200003];

int n;

int a[200003];
int d[200003];
int ans = 0;
int st;

int main () {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]),
		ma[i].oldnum = a[i],
		ma[i].oldid = i;
	std:: sort(ma + 1, ma + n + 1);
	for (int i = 1; i <= n; i++)
		if (ma[i].oldnum == ma[i - 1].oldnum)
			ma[i].truerank = ma[i - 1].truerank;
		else
			ma[i].truerank = i;
	for (int i = 1; i <= n; i++)
		a[ma[i].oldid] = ma[i].truerank;
	for (int i = n; i >= 1; i--) {
		d[a[i]] = d[a[i] + 1] + 1;
		if (ans < d[a[i]]) {
			st = a[i];
			ans = d[a[i]];
		}
	}
	printf("%d\n", ans);
	for (int i = 1; i <= n; i++)
		if (a[i] == st)
			printf("%d ", i),
			st++;
	return 0;
}

为什么会 WA 呢?

给个例子, 输入 2 1 3 时离散化 \(A\) 成为 \(\{1, 2\}\), 这样做时程序就会以为产生误判, 原本不连续的两个数被离散化连续了.

那么只要将原本不连续的两个数离散化之后还是不连续不就行了吗! 我们在离散化时将原本不连续的两个数中间隔一个数就可以了, 原来的公式仍然成立!

代码

#include <stdio.h>
#include <algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))

struct NODE {
	int oldnum;
	int oldid;
	int truerank;
	const inline bool operator < (const NODE &rhs) const {
		return oldnum < rhs.oldnum;
	}
} ma[200003];

int n;

int a[400003];
int d[400003];
int ans = 0;
int st;

int main () {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]),
		ma[i].oldnum = a[i],
		ma[i].oldid = i;
	std:: sort(ma + 1, ma + n + 1);
	for (int i = 1; i <= n; i++)
		if (ma[i].oldnum == ma[i - 1].oldnum)
			ma[i].truerank = ma[i - 1].truerank;
		else if (ma[i - 1].oldnum + 1 == ma[i].oldnum)	// 可以 AC 的离散化, 好耶!! 
			ma[i].truerank = ma[i - 1].truerank + 1;
		else
			ma[i].truerank = ma[i - 1].truerank + 2;
	for (int i = 1; i <= n; i++)
		a[ma[i].oldid] = ma[i].truerank;
	for (int i = n; i >= 1; i--) {
		d[a[i]] = d[a[i] + 1] + 1;
		if (ans < d[a[i]]) {
			st = a[i];
			ans = d[a[i]];
		}
	}
	printf("%d\n", ans);
	for (int i = 1; i <= n; i++)
		if (a[i] == st)
			printf("%d ", i),
			st++;
	printf("\n");
	return 0;
}
posted @ 2021-09-21 22:33  dbg_8  阅读(54)  评论(0编辑  收藏  举报