您的位置:首页 > 产品设计 > UI/UE

CF 277 Div2 E LIS of Sequence

2015-01-18 00:15 441 查看
E. LIS of Sequence

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

The next "Data Structures and Algorithms" lesson will be about Longest Increasing Subsequence (LIS for short) of a sequence. For better understanding, Nam decided to learn it a few days before the lesson.

Nam created a sequence a consisting of
n (1 ≤ n ≤ 105) elementsa1, a2, ..., an
(1 ≤ ai ≤ 105). A subsequence
ai1, ai2, ..., aik
where 1 ≤ i1 < i2 < ... < ik ≤ n is called increasing ifai1 < ai2 < ai3 < ... < aik.
An increasing subsequence is called longest if it has maximum length among all increasing subsequences.

Nam realizes that a sequence may have several longest increasing subsequences. Hence, he divides all indexesi (1 ≤ i ≤ n), into three groups:

group of all i such that
ai belongs to no longest increasing subsequences.
group of all i such that
ai belongs to at least onebut not every longest increasing subsequence.
group of all i such that
ai belongs to every longest increasing subsequence.

Since the number of longest increasing subsequences of
a may be very large, categorizing process is very difficult. Your task is to help him finish this job.

Input
The first line contains the single integer n (1 ≤ n ≤ 105) denoting the number of elements of sequencea.

The second line contains n space-separated integersa1, a2, ..., an
(1 ≤ ai ≤ 105).

Output
Print a string consisting of n characters.i-th character should be '1', '2' or '3'
depending on which group among listed above indexi belongs to.

Sample test(s)

Input
1
4


Output
3


Input
4
1 3 2 5


Output
3223


Input
4
1 5 2 3


Output
3133


Note
In the second sample, sequence a consists of 4 elements:{a1, a2, a3, a4}
={1, 3, 2, 5}. Sequence a has exactly 2 longest increasing subsequences of length 3, they are{a1, a2, a4}
={1, 3, 5} and {a1, a3, a4} ={1, 2, 5}.

In the third sample, sequence a consists of 4 elements:{a1, a2, a3, a4}
={1, 5, 2, 3}. Sequence a have exactly 1 longest increasing subsequence of length 3, that is{a1, a3, a4}
={1, 2, 3}.

解析

LIS问题,先从前往后跑一个最长上升子序列L,再从后往前跑一个最长下降子序列R。其实从前往后看两者都是上升的,注意L[i]<>R[i]。

对于第一类始终不在LIS中的,一定有L[i]+R[i]-1<maxl(其中maxl是最长上升子序列)。

除开第一类看,L[i]只出现过一次的是第三类,多次的是第二类。

一定要用O(nlogn)的动规(新技能get)讲解

题目:

给出一个由n个数组成的序列x[1..n],找出它的最长单调上升子序列。即求最大的m和a1,

a2……,am,使得a1<a2<……<am且x[a1]<x[a2]<……<x[am]。要求时间复杂度O(nlgn)

这也是一道动态规划的经典应用。一种动态规划的状态表示描述为:m[i],1≤i≤n,表示以x[i]结尾的最长上升子序列的长度,则问题的解为 max{m[i],1≤i≤n},状态转移方程和边界条件为:

m[i]=1+max{0, m[k]|x[k]<x[i] , 1≤k<i }同时当m[i]>1时,令p[i]=k,表示最优决策,

以便在计算出最优值后构造最长单调上升子序列。

上述算法的状态总数为O(n),每个状态转移的状态数最多为O(n),每次状态转移的时间为

O(1),所以算法总的时间复杂度为O(n2)。

我们先来考虑以下两种情况:

1、若x[i]<x[j],m[i]=m[j],则m[j]这个状态不必保留。因为,可以由状态m[j]转移得到

的状态m[k] (k>j,k>i),必有x[k]>x[j]>x[i],则m[k]也能由m[i]转移得到;另一方面,

可以由状态m[i]转移得到的状态m[k] (k>j,k>i),当x[j]>x[k]>x[i]时,m[k]就无法由m

[j]转移得到。

由此可见,在所有状态值相同的状态中,只需保留最后一个元素值最小的那个状态即可。

2、若x[i]<x[j],m[i]>m[j],则m[j]这个状态不必保留。因为,可以由状态m[j]转移得到的状态m[k] (k>j,k>i),必有x[k]>x[j]>x[i],则m[k]也能由m[i]转移得到,而且m[i]>m[j],所以m[k]≥m[i]+1>m[j]+1,则m[j]的状态转移是没有意义的。

综合上述两点,我们得出了状态m[k]需要保留的必要条件:不存在i使得:x[i]<x[k]且m[i]≥m[k]。

于是,我们保留的状态中不存在相同的状态值,且随着状态值的增加,最后一个元素的值

也是单调递增的。

也就是说,设当前保留的状态集合为S,则S具有以下性质D:

对于任意i∈S, j∈S, i≠j有:m[i]≠m[j],且若m[i]<m[j],则x[i]<x[j],否则x[i]>x[j]。

下面我们来考虑状态转移:假设当前已求出m[1..i-1],当前保留的状态集合为S,下面计

算m[i]。

1、若存在状态k∈S,使得x[k]=x[i],则状态m[i]必定不需保留,不必计算。因为,不妨

设m[i]=m[j]+1,则x[j]<x[i]=x[k],j∈S,j≠k,所以m[j]<m[k],则m[i]=m[j]+1≤m[k],所以状态m[i]不需保留。

2、否则,m[i]=1+max{m[j]| x[j]<x[i], j∈S}。我们注意到满足条件的j也满足x[j]=max{x[k]|x[k]<x[i], k∈S}。同时我们把状态i加入到S中。

3、若2成立,则我们往S中增加了一个状态,为了保持S的性质,我们要对S进行维护,若存

在状态k∈S,使得m[i]=m[k],则我们有x[i]<x[k],且x[k]=min{x[j]|x[j]>x[i], j∈S}。于是状态k应从S中删去。

于是,我们得到了改进后的算法:

For i:=1 to n do

{

找出集合S中的x值不超过x[i]的最大元素k;

if x[k]<x[i] then

{

m[i]:=m[k]+1;

将状态i插入集合S;

找出集合S中的x值大于x[i]的最小元素j;

if m[j]=m[i] then 将状态j从S中删去;

}

}

从性质D和算法描述可以发现,S实际上是以x值为关键字(也是以m值为关键字)的有序集

合。

若使用平衡树实现有序集合S,则该算法的时间复杂度为O(n*log2n)。(每个状态转移的状

态数仅为O(1),

而每次状态转移的时间变为O(log2n))

还有就是从后往前跑一个最长下降子序列的时候,要在一个单减的数列里用lower_bound,有个小小的技巧,在每个数前面加个负号就变成单增的了。

#include<cstdio>
#include<algorithm>
#include<set>
#include<cstring>

using namespace std;

#define LOCAL

#define INF 0x3f3f3f3f

int L[100100],R[100100],g[100100],N,Arr[100100],ans[100100],cnt[100100],maxl;//dp[i] is method

void Dynamic_Planning()
{
maxl=0;
//最长上升子序列
memset(g,0x3f,sizeof(g));
for(int i=1;i<=N;i++)
{
int k=lower_bound(g+1,g+N+1,Arr[i])-g;
L[i]=k;
if(g[k]==INF) maxl++;
g[k]=Arr[i];
}

//最长下降子序列
memset(g,0x3f,sizeof(g));
for(int i=N;i>0;i--)
{
int k=lower_bound(g+1,g+N+1,-Arr[i])-g;
R[i]=k;
g[k]=-Arr[i];
}
#ifdef LOCA
printf("%d\nL:",maxl); for(int i=1;i<=N;i++) printf("%d ",L[i]); puts("");
printf("R:"); for(int i=1;i<=N;i++) printf("%d ",R[i]); puts("");
#endif
}

void write()
{
memset(ans,0,sizeof(ans));
memset(cnt,0,sizeof(cnt));

for(int i=1;i<=N;i++)
if(L[i]+R[i]<maxl+1) ans[i]=1;
else cnt[L[i]]++;

for(int i=1;i<=N;i++)
if(ans[i]) printf("%d",ans[i]);
else if(cnt[L[i]]==1) printf("3");
else printf("2");
printf("\n");
}

int main()
{
#ifdef LOCAL
freopen("C.in","r",stdin);
#endif

while(scanf("%d",&N)==1)
{
for(int i=1;i<=N;i++) L[i]=R[i]=1,scanf("%d",&Arr[i]);
Dynamic_Planning();
write();
}

#ifdef LOCAL
while(1);
#endif

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: