51Nod 1376 最长递增子序列的数量 —— LIS、线段树

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376

 

1376 最长递增子序列的数量 

基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题

 

 收藏

 

 关注

 

数组A包含N个整数(可能包含相同的值)。设S为A的子序列且S中的元素是递增的,则S为A的递增子序列。如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS)。A的LIS可能有很多个。例如A为:{1 3 2 0 4},1 3 4,1 2 4均为A的LIS。给出数组A,求A的LIS有多少个。由于数量很大,输出Mod 1000000007的结果即可。相同的数字在不同的位置,算作不同的,例如 {1 1 2} 答案为2。

Input

第1行:1个数N,表示数组的长度。(1 <= N <= 50000)

第2 - N + 1行:每行1个数A[i],表示数组的元素(0 <= A[i] <= 10^9)

Output

输出最长递增子序列的数量Mod 1000000007。

Input示例

5

1

3

2

0

4

Output示例

2

 

题解:

1.由于要统计个数,所以就不能用之前所谓的O(n^2)或O(nlogn)方法(这两种方法求的是LIS的长度,而不是个数)。

2.因此需要利用线段树进行统计:将输入的值进行离散化,然后在离散化后数组之上建立线段树(即以值建树而不是以下标建树)。线段树的每个结点需要记录两个信息: 该段的LIS的长度及个数。

 

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 5e4+10;
18 
19 pair<int,int> getMax(pair<int,int> x, pair<int,int>y)
20 {
21     if(x.first<y.first) x = y;
22     else if(x.first==y.first) x.second = (x.second+y.second)%MOD;
23     return x;
24 }
25 
26 pair<int,int> len[MAXN*4];
27 void build(int u, int l, int r)
28 {
29     if(l==r)
30     {
31         len[u].first = len[u].second = 0;
32         return;
33     }
34     int mid = (l+r)>>1;
35     build(u*2,l,mid);
36     build(u*2+1,mid+1,r);
37     len[u] = getMax(len[u*2],len[u*2+1]);
38 }
39 
40 void add(int u, int l, int r, int pos, pair<int,int> val)
41 {
42     if(l==r)
43     {
44         len[u] = getMax(len[u],val);
45         return;
46     }
47     int mid = (l+r)>>1;
48     if(pos<=mid) add(u*2,l,mid,pos,val);
49     else add(u*2+1,mid+1,r,pos,val);
50     len[u] = getMax(len[u*2],len[u*2+1]);
51 }
52 
53 pair<int,int> query(int u, int l, int r, int x, int y)
54 {
55     if(x<=l&&r<=y) return len[u];
56 
57     int mid = (l+r)>>1;
58     pair<int,int> ret = make_pair(0,0);
59     if(x<=mid) ret = getMax(ret,query(u*2,l,mid,x,y));
60     if(y>=mid+1) ret = getMax(ret,query(u*2+1,mid+1,r,x,y));
61     return ret;
62 }
63 
64 int a[MAXN], M[MAXN], m;
65 int main()
66 {
67     int n;
68     while(scanf("%d",&n)!=EOF)
69     {
70         for(int i = 1; i<=n; i++)
71             scanf("%d",&a[i]);
72 
73         memcpy(M+1,a+1,n*sizeof(a[0]));
74         M[n+1] = -INF;  //在最前面加个无穷小,防止区间溢出
75         sort(M+1,M+1+n+1);         //离散化
76         m = unique(M+1,M+1+n+1)-(M+1);
77 
78         build(1,1,m);
79         for(int i = 1; i<=n; i++)
80         {
81             int pos = lower_bound(M+1,M+1+m,a[i])-(M+1);    //找到a[i]的上一个值的位置(这也是为什么要在离散化数组里加个无穷小)
82             pair<int,int> t = query(1,1,m,1,pos);
83             if(t.first==0) t.first = t.second = 1;  //如果在前面没人比它小,则自己作为第一个
84             else t.first++;     //如果前面有人比它小,则长度+1(加上自己)
85             add(1,1,m,pos+1,t);     //插入
86         }
87         printf("%d\n", query(1,1,m,1,m).second);
88     }
89 }
View Code

 

posted on 2018-04-04 22:18  h_z_cong  阅读(426)  评论(0编辑  收藏  举报

导航