题目: LINK
求一个串的LIS 最长递增子序列,有可能LIS不唯一。
对于每一个a[i] 有三种可能: 1, 不属于任何LIS。 2,属于某些LIS,但不属于全部LIS。 3,属于全部的LIS;
n大小为1e5
对于求LIS要用nlog(n)的算法,分别求出f1[i], f2[i] , f1[i] 表示包含a[i]的a[1~i]中的LIS长度,f2[i]表示包含a[i]的a[i~n]中的LIS长度.
如果f1[i] + f2[i] - 1 < lis 说明a[i]不包含于任何LIS
如果 设w = f1[i], 只出现一次w + f2[x] - 1 == lis 那么 a[i] 包含于任何LIS中
否则 只包含于某一些LIS中
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define INF 1000000000
//typedef __int64 LL;
#define N 111111
int a[N], f1[N], f2[N], sta[N], top, n;
int vis[N];
int b_search1(int x, int l ,int r) {
int m, ret;
while(l <= r) {
m = (l+r)>>1;
if(sta[m] >= x ) ret = m, r = m - 1;
else l = m + 1;
}
return ret;
}
int b_search2(int x, int l , int r) {
int m , ret;
while(l <= r) {
m = (l+r) >> 1;
if(sta[m] <= x) ret = m, r = m - 1;
else l = m + 1;
}
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d", &n);
for(int i = 1;i <= n; i ++) {
scanf("%d", &a[i]);
}
top = 0;
for(int i = 1;i <= n; i++) {
if(top == 0 || sta[top] < a[i]) {
top ++;
sta[top] = a[i];
f1[i] = top;
}
else {
int id = b_search1(a[i], 1, top);
sta[id] = a[i];
f1[i] = id;
}
}
top = 0;
for(int i = n; i >= 1; i --) {
if(top == 0 || sta[top] > a[i]){
top ++;
sta[top] = a[i];
f2[i] = top;
}
else {
int id = b_search2(a[i], 1, top);
sta[id] = a[i];
f2[i] = id;
}
}
int lis = top;
for(int i = 1;i <= n; i++) {
if(f1[i] + f2[i] - 1 == lis) {
vis[f1[i]] ++;
}
}
for(int i = 1; i <= n; i ++) {
if(f1[i] + f2[i] - 1 < lis) printf("1");
else if(vis[f1[i]] == 1) printf("3");
else printf("2");
}
puts("");
return 0;
}