zoukankan      html  css  js  c++  java
  • 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
    ", query(1,1,m,1,m).second);
    88     }
    89 }
    View Code
  • 相关阅读:
    angular4 跨域携带cookie的设置
    引入第三方库jquery
    禁用输入框 浏览器的自动补全功能
    Mongodb 安装和启动
    chrome浏览器的表单自动填充
    jquery原生对象
    js获取文档高度
    字体在各个浏览器中的样式问题
    jquery中的ajax参数说明
    JavaScript中的面向对象
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8719525.html
Copyright © 2011-2022 走看看