Codeforces Round #277 (Div. 2) E. LIS of Sequence

题目: 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; 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值