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

Posted fisherss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 >>><
*/

思考人生

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

以上是关于CF-div2-620-D. Shortest and Longest LIS 贪心,双指针的主要内容,如果未能解决你的问题,请参考以下文章

CF-div2-630-B - Composite Coloring

CF-div3-635-E - Three Blocks Palindrome| 二分

CF-Div2-832 D. Yet Another Problem(bitmask&结论)

CF-Div2-832 D. Yet Another Problem(bitmask&结论)

CF-div3-611-F. DIY Garland 优先队列 构造树

LeetCode 821. Shortest Distance to a Character