其他分享
首页 > 其他分享> > CF1682C LIS or Reverse LIS?

CF1682C LIS or Reverse LIS?

作者:互联网

题目大意:

设一个长为n的整数序列a是 [a_1,a_2,a_3,......,a_n]那么a'是 [a_n,a_n-1,a_n-2,......,a_1]LIS(a) 是a的最长严格递增子序列的长度。
现在给定a数组,对数组进行重排后,求min(LIS(a),LIS(a′))的最大值。
输入t组数据,每组数据先输入n,然后输入n个整数
输出t行,每行一组数据的答案,按输入顺序。

  其实正解是不难想到的(可是原题翻译错了)。既然可以重排,又需要使数组顺序和逆序两种情况的LIS都尽可能大,那么思路就显而易见了:把所有数中最大的数放在数列的最中间,把剩下的数分成两部分,一部分放在最中间数的左边,要求这一部分的数按大小不下降进行排列,另一部分放在右边,要求按照大小不上升进行排列,同时,让这两部分数的个数尽可能相等。
  注意到,在整个数列中,一种数的贡献最多为2,当它的个数为2时,一个放在左边,一个放在右边,如果大于2的话,那就无法有更多的贡献了。。因此我们需要记录每个数出现的次数,如果出现次数大于2,就不加上它的贡献。这样,遍历整个数列,加上贡献,最后除以二即可(因为加的是两边数列所有数的贡献),考虑到数可能很大,这里用map进行优化
  然而这里有个特例,对于最中间的那一个数,它的贡献始终为2,因为左边的最长上升序列的终点是它,右边的最长下降序列的起点也是它,特殊处理即可。

//2022/7/12 
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10000;
int t,n;
map<int,int> a;
int main(){
	cin >> t;
	while(t--){
		cin >> n;
		int ans = 0,b;
		a.clear();
		for(int i = 1; i <= n ; i++){
			cin >> b;//一边输入,一边处理 
			a[b]++;
			if(a.find(b) == a.end() || (a.find(b) != a.end() && a[b] <= 2))ans++;//如果该数出现次数小于二,加上该数的贡献,并把出现次数加一 
		}
		cout << (ans + 1) / 2 << "\n";//处理最中间的数这一特殊情况 ,记得除以2哦 
	}
} 

标签:Reverse,int,贡献,LIS,序列,CF1682C,输入,数列
来源: https://www.cnblogs.com/CZ-9/p/16471773.html