CF-div2-620-D. Shortest and Longest LIS 贪心,双指针

思路

0.首先思考什么时候产生LIS上升的贡献,肯定是遇到了一个小于号啊,左边 < 右边。就产生贡献2
举例:比如 3<5 那么产生了贡献的长度为2; 再比如 5>4 大于号肯定不产生LIS的贡献了,。

假设上面想到了。
接下来考虑怎么找最短,和最长。

再等等,思考还有没有产生贡献的地方?
容易想到就是** 小于号 与 小于号 之间 也会产生贡献。**
比如 3<5>4<6; 那么3,5,6这三个数就产生了贡献,即两个小于号也可能产生贡献。

1.考虑找最短,有了上面的思考,容易想到,一个小于号产生的贡献我们肯定无法改变了,那么考虑“小于号与小于号之间”的贡献我们怎么把它给减小
容易想到,如果 前面的小于号左右两边值,比,后面的小于号左右两边值大,那么这样就能消除 “小于号与小于号之间的贡献”
比如 3<5>2<1, 这样3,5,1就不能构成LIS,只有3,5能构成LIS,产生贡献2;
比如 3<5>4<6,这样3,5,6都能构成LIS,产生贡献3;

所以我们,就把数字从大往小放,这样能保证“小于号与小于号之间不构成LIS”
用双指针,每次以连续小于号为一组,从这一组的最后开始往前放数字(数字从大到小),这样能保证小于号与小于号之间不构成LIS,使之最短。
总结:尽量使大的数在前面

2.考虑找最长,同上理解,
所以我们,就把数字从小往大放,这样能保证“小于号与小于号之间也构成LIS”
用双指针,每次以连续大于号为一组,从这一组的最后开始往前放数字(数字从小到后),这样能保证小于号与小于号之间构成LIS,使之最长。
为什么这里以大于号为一组呢,因为我们是从小往后放数字的,为了保证小于号之间是能产生贡献的
总结:尽量使小的数在前面。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2e5+10;
int t;
int n;
string s;
int mina[maxn],maxb[maxn];

int main(){
	cin>>t;
	while(t--){
		cin>>n;
		cin>>s;
		//找最短 
		int maxNum = n; //从大往前放 就能确保各个小于号  大的在前 小的数在后
		for(int i=0;i<s.length();i++){
			int len = 0;
			if(s[i] == '<'){ //找连续的小于号 
				while(s[i] == '<'){
					len++;
					i++;
				}
			}
			//从后往前放数字 以保证后面大前面小 
			for(int j=i;j>=i-len;j--){
				mina[j] = maxNum--;
			}
		}
		if(maxNum != 0) mina[n-1] = maxNum;
		//找最长 
		int minNum = 1; //从小的数开始放  就能确保 各个小于号, 小的在前 大的在后 这样就能产生递增的贡献
		for(int i=0;i<s.length();i++){
			int len = 0;
			if(s[i] == '>'){
				while(s[i] == '>'){
					len++;
					i++;
				}
			}
			//从后往前放数字 以保证后面小前面大
			for(int j=i;j>=i-len;j--){
				maxb[j] = minNum++;
			}
		}
		if(minNum == n) maxb[n-1] = n;
		for(int i=0;i<=n-1;i++) cout<<mina[i]<<" ";
		cout<<endl;
		for(int i=0;i<=n-1;i++) cout<<maxb[i]<<" ";
		cout<<endl;
	}
	return 0;
}
/*
3
3 <<
7 >><>><
5 >>><
*/

思考人生

感觉自己挺废的,想了一两个小时没想出来,看了题解才知道,真的废啊啊啊
这样也好,看完题解,按自己的方式理解,总比不写好,不写永远不知道自己有多菜,虽然一下午就干这一道题了。
自己选择的路,好好走完吧。

posted @ 2020-02-29 17:19  fishers  阅读(145)  评论(0编辑  收藏  举报