题意:n-1个'>''<'的字符串,我们要构造一个长度为n的包含整数[1, n]的序列a[ ]。对于每个s[ i ] == '<'表示a[ i ] < a[ i + 1 ],对于s[ i ] == '>'表示a[ i ] > a[ i + 1 ]。我们找到两个满足条件的序列,输出一个LIS最短的序列,输出一个LIS最长的序列。
思路
我们将'<'用1替代,将'>'用0替代,构造一个01串,并且在该01串的首位置加一个1. 于是我们得到了一个长度为n的01串。
0代表什么呢?所有0都是连续的下降序列!
1代表什么呢?
- 如果对于所有的1,我们是连续的上升序列,显然可以得到最长的LIS
- 如果对于所有的“1的块”,每个块单调递减【块内连续上升;块间,每个块内最大值递减】
举个栗子
8 >><>><<
10010011
43 21
5 6 78
8 7 56
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 200005;
int n;
int ans[2][maxN];
char s[maxN];
struct node{
int l, r;
node() {}
node(int a, int b): l(a), r(b) {}
}info[maxN];
int main()
{
int TAT; TAT = read();
while(TAT --)
{
n = read();
scanf("%s", s);
int tot = 0, last = 1, now = 1;
string _01 = "1";
for(int i = 0; i < n - 1; ++ i )
if(s[i] == '<')
_01 += '1';
else
_01 += '0';
for(int i = 0; i < n; ++ i )
{
if(_01[i] == '1')
{
if(last)
info[tot].r = i;
else
info[++ tot] = node(i, i), last = 1;
}
else
last = 0;
}
for(int i = n - 1; i >= 0; -- i)
if(_01[i] == '0') ans[0][i] = ans[1][i] = now ++;
int tmp = now;
//处理最长上升子序列
for(int i = 0; i <= tot; ++ i )
{
for(int j = info[i].l; j <= info[i].r; ++ j )
ans[1][j] = tmp ++;
}
//处理最短上升子序列
tmp = now;
for(int i = tot; i >= 0; -- i)
{
for(int j = info[i].l; j <= info[i].r; j ++ )
ans[0][j] = tmp ++ ;
}
for(int i = 0; i < n; ++ i )
printf("%d%c", ans[0][i], " \n"[i == n - 1]);
for(int i = 0; i < n; ++ i )
printf("%d%c", ans[1][i], " \n"[i == n - 1]);
}
return 0;
}