CF1304D Shortest and Longest LIS

Problem Link

一种很巧妙的做法

我们从第二个样例开始讲

想要 LIS 最小,我们就先这样放置

7 6 5 4 3 2 1

然后如果碰到一连串的小于号,那就把那一段小于号所在的数字段整段翻转

也就是说

 > > < > > <
7 6 4 5 3 1 2

第一个小于使得 4 5 被翻转,第二个 < 使得 1 2 被翻转

这样 LIS 就为最大连续小于号的长度,无论如何 LIS 都没办法小于这个

要想 LIS 最大,反过来就行了

先放置

1 2 3 4 5 6 7

如果碰到一连串的大于号,那就把那一段大于号所在的数字段整段翻转

 > > < > > <
3 2 1 6 5 4 7

这样 LIS 就为连续小于号段的数量+1,无论如何 LIS 都没办法大于这个

于是就 \(O(n)\) 搞定了

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
using namespace std;
/*
template <class t> inline void read(t &s)
{
    s=0;
    reg int f=1;
    reg char c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    s*=f;
    return;
}
*/
char s[200050];
int a[200050];
inline void myrev(int l,int r)
{
    reg int delta=l-1;
    reg int n=r-l+1;
    for(int i=1;i<=n/2;++i)
        swap(a[delta+i],a[delta+n-i+1]);
    return;
}
inline void work()
{
    reg int n;
    cin>>n;
    cin>>(s+1);
    for(int i=1;i<=n;++i)
        a[i]=n-i+1;
    reg int cnt=0;
    for(int i=1;i<n;++i)
        if(s[i]=='<')
            ++cnt;
        else if(cnt)
            myrev(i-cnt,i),cnt=0;
    if(cnt)
        myrev(n-cnt,n);
    for(int i=1;i<=n;++i)
        cout<<a[i]<<" ";
    cout<<endl;
    for(int i=1;i<=n;++i)
        a[i]=i;
    cnt=0;
    for(int i=1;i<n;++i)
        if(s[i]=='>')
            ++cnt;
        else if(cnt)
            myrev(i-cnt,i),cnt=0;
    if(cnt)
        myrev(n-cnt,n);
    for(int i=1;i<=n;++i)
        cout<<a[i]<<" ";
    cout<<endl;
    return;
}
signed main(void)
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--)
        work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chinesepikaync/p/12316201.html