#C240930A. Longest Max Min Subsequence


#C240930A. Longest Max Min Subsequence

标签(Label)

  • 单调栈
  • 贪心

网址(Website)

Longest Max Min Subsequence - 洛谷

Problem - 2001D - Codeforces

题目(Problem)

题目描述

给你一个整数序列 $a_1,a_2,\ldots,a_n$ 。设 $S$ 是 $a$ 的所有可能的非空子序列的集合,且没有重复的元素。你的目标是找出 $S$ 中最长的序列。如果有多个序列,请找出将奇数位置上的项乘以 $-1$ 后,使词序最小的序列。

例如,给定 $a = [3, 2, 3, 1]$ , $S = \{[1], [2], [3], [2, 1], [2, 3], [3, 1], [3, 2], [2, 3, 1], [3, 2, 1]\}$。那么 $[2, 3, 1]$ 和 $[3, 2, 1]$ 将是最长的,而 $[3, 2, 1]$ 将是答案,因为 $[-3, 2, -1]$ 的词序小于 $[-2, 3, -1]$ 。

如果 $c$ 可以通过删除几个(可能是零个或全部)元素从 $d$ 得到,那么序列 $c$ 就是序列 $d$ 的子序列。

当且仅当以下条件之一成立时,序列 $c$ 在词法上小于序列 $d$ :

  • $c$ 是 $d$ 的前缀,但 $c \ne d$ ;
  • 在 $c$ 和 $d$ 不同的第一个位置,序列 $c$ 中的元素小于 $d$ 中的相应元素。

输入

每个测试包含多个测试用例。第一行包含测试用例的数量 $t$ ( $1 \le t \le 5 \cdot 10^4$ )。测试用例说明如下。

每个测试用例的第一行包含一个整数 $n$ ( $1 \le n \le 3 \cdot 10^5$ ) - $a$ 的长度。

每个测试用例的第二行包含 $n$ 个整数 $a_1, a_2, \ldots, a_n$ ( $1 \le a_i \le n$ ) - 序列 $a$ 。

保证所有测试用例中 $n$ 的总和不超过 $3 \cdot 10^5$ 。

输出

对于每个测试用例,按以下格式输出答案:

在第一行输出整数 $m$ - $b$ 的长度。

然后在第二行输出 $m$ 个整数 $b_1, b_2, \ldots, b_m$ - 序列 $b$ 。

样例输入1

4
4
3 2 1 3
4
1 1 1 1
9
3 2 1 3 2 1 3 2 1
1
1

样例输出1

3
3 2 1
1
1
3
3 1 2
1
1

样例输入2

10
2
1 2
10
5 2 1 7 9 7 2 5 5 2
2
1 2
10
2 2 8 7 7 9 8 1 9 6
9
9 1 7 5 8 5 6 4 1
3
3 3 3
6
1 6 4 4 6 5
6
3 4 4 5 3 3
10
4 1 4 5 4 5 10 1 5 1
7
1 2 1 3 2 4 6

样例输出2

2
1 2
5
5 1 9 7 2
2
1 2
6
2 7 9 8 1 6
7
9 1 7 5 8 6 4
1
3
4
1 4 6 5
3
4 5 3
4
5 4 10 1
5
2 1 3 4 6

在第一个例子中, $S = {[1], [2], [3], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2], [2, 1, 3], [3, 2, 1]}$ 。其中, $[2, 1, 3]$ 和 $[3, 2, 1]$ 最长,而 $[-3, 2, -1]$ 比 $[-2, 1, -3]$ 的词性小,所以 $[3, 2, 1]$ 是答案。

在第二个例子中, $S = {[1]}$ ,所以 $[1]$ 是答案。

题解(Solution)

推荐一篇题解: Longest Max Min Subsequence - 洛谷专栏

$\qquad$要让获得的序列奇数位最大,偶数为最小。我们先考虑让所有位最大的情况,发现直接维护一个单调递减的单调栈就可以解决问题。如果当前 $a[i]$ 在单调栈内,那么直接跳过(单调栈里面的一定是保证最优的);如果不在,考虑弹出栈顶,注意如果这个 $a[i]$ 后面不会再出现,就不能删除,可以用一个 $lst$ 数组预处理解决这个问题。

$\qquad$考虑使用单调栈解决更复杂的问题,每次得到 $a[i]$ 的时候考虑和栈顶和栈的次顶比较,分类讨论所有情况,发现直接使用 $STL$ 包装的 $stack$ 难以获取第二位栈顶,直接换成 $vector$ 即可。

$\qquad$时间复杂度:$O(n)$ 。

代码(Code)

#include<bits/stdc++.h>
#include<vector>
#include<stack>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int>
#define int long long
#define x first
#define y second
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 301234;
bool ST;

bitset<N> hav;
int n,a[N];

vector<int> st;
inline void out(int x){
	while(x--){
		hav[st.back()] = false;
		st.pop_back();
	}
}

int lst[N];
inline int solve(){
	st.clear(), hav.reset();
	For(i,1,n) lst[i] = 0;
	Rof(i,n,1) if(!lst[a[i]]) lst[a[i]] = i;
	For(i,1,n){
		if(st.empty()) st.emplace_back(a[i]),hav[a[i]]=true;
		if(hav[a[i]]) continue;
		while(st.size() >= 2){
			int c1 = *prev(st.end(),2), c2 = *prev(st.end());
			bool f = false;
			if(!f && i<lst[c1] && i<lst[c2]){
				if(st.size()&1) {if(a[i] < c1) out(2),f = true;}
				else 			{if(a[i] > c1) out(2),f = true;}
			}
			if(!f && i<lst[c2]){
				if(st.size()&1) {if(a[i] > c2) out(1),f = true;}
				else 			{if(a[i] < c2) out(1),f = true;}
			}
			if(!f) break;
		}if(st.size()==1 && i<lst[st.back()] && a[i]>st.back()) out(1);//判断只剩一个的情况 
		
		st.emplace_back(a[i]), hav[a[i]] = true;
	}return st.size();
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	int T=rd(),Tim = clock();
	while(T--){
		n = rd();For(i,1,n) a[i] = rd();
		printf("%lld\n",solve());
		for(auto i=st.begin();i!=st.end();i++){
			printf("%lld",*i);
			if(i!=prev(st.end())) printf(" ");//这个地方很逆天
		}printf("\n");
	}return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录