题目链接: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的长度及个数。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 5e4+; pair<int,int> getMax(pair<int,int> x, pair<int,int>y)
{
if(x.first<y.first) x = y;
else if(x.first==y.first) x.second = (x.second+y.second)%MOD;
return x;
} pair<int,int> len[MAXN*];
void build(int u, int l, int r)
{
if(l==r)
{
len[u].first = len[u].second = ;
return;
}
int mid = (l+r)>>;
build(u*,l,mid);
build(u*+,mid+,r);
len[u] = getMax(len[u*],len[u*+]);
} void add(int u, int l, int r, int pos, pair<int,int> val)
{
if(l==r)
{
len[u] = getMax(len[u],val);
return;
}
int mid = (l+r)>>;
if(pos<=mid) add(u*,l,mid,pos,val);
else add(u*+,mid+,r,pos,val);
len[u] = getMax(len[u*],len[u*+]);
} pair<int,int> query(int u, int l, int r, int x, int y)
{
if(x<=l&&r<=y) return len[u]; int mid = (l+r)>>;
pair<int,int> ret = make_pair(,);
if(x<=mid) ret = getMax(ret,query(u*,l,mid,x,y));
if(y>=mid+) ret = getMax(ret,query(u*+,mid+,r,x,y));
return ret;
} int a[MAXN], M[MAXN], m;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i = ; i<=n; i++)
scanf("%d",&a[i]); memcpy(M+,a+,n*sizeof(a[]));
M[n+] = -INF; //在最前面加个无穷小,防止区间溢出
sort(M+,M++n+); //离散化
m = unique(M+,M++n+)-(M+); build(,,m);
for(int i = ; i<=n; i++)
{
int pos = lower_bound(M+,M++m,a[i])-(M+); //找到a[i]的上一个值的位置(这也是为什么要在离散化数组里加个无穷小)
pair<int,int> t = query(,,m,,pos);
if(t.first==) t.first = t.second = ; //如果在前面没人比它小,则自己作为第一个
else t.first++; //如果前面有人比它小,则长度+1(加上自己)
add(,,m,pos+,t); //插入
}
printf("%d\n", query(,,m,,m).second);
}
}

51Nod 1376 最长递增子序列的数量 —— LIS、线段树的更多相关文章

  1. 51nod 1376 最长递增子序列的数量(线段树)

    51nod 1376 最长递增子序列的数量 数组A包含N个整数(可能包含相同的值).设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递 ...

  2. 51NOD 1376 最长递增子序列的数量 [CDQ分治]

    1376 最长递增子序列的数量 首先可以用线段树优化$DP$做,转移时取$0...a[i]$的最大$f$值 但我要练习$CDQ$ $LIS$是二维偏序问题,偏序关系是$i<j,\ a_i< ...

  3. 51nod 1376 最长递增子序列的数量(不是dp哦,线段树 +  思维)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376 题解:显然这题暴力的方法很容易想到就是以每个数为结尾最 ...

  4. 51Nod 1376 最长递增子序列的数量 (DP+BIT)

    题意:略. 析:dp[i] 表示以第 i 个数结尾的LIS的长度和数量,状态方程很好转移,先说长度 dp[i] = max { dp[j] + 1 | a[i] > a[j] && ...

  5. 51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!

    51nod 1376 最长上升子序列的数量 题解 我们设lis[i]为以位置i结尾的最长上升子序列长度,dp[i]为以位置i结尾的最长上升子序列数量. 显然,dp[i]要从前面的一些位置(设为位置j) ...

  6. 【51nod】1376 最长递增子序列的数量

    数组A包含N个整数(可能包含相同的值).设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS).A的LIS可能有很多个. ...

  7. 51nod1376 最长递增子序列的数量

    O(n2)显然超时.网上找的题解都是用奇怪的姿势写看不懂TAT.然后自己YY.要求a[i]之前最大的是多少且最大的有多少个.那么线段树维护两个值,一个是当前区间的最大值一个是当前区间最大值的数量那么我 ...

  8. 51nod 1134 最长递增子序列

    题目链接:51nod 1134 最长递增子序列 #include<cstdio> #include<cstring> #include<algorithm> usi ...

  9. 51nod 1218 最长递增子序列 | 思维题

    51nod 1218 最长递增子序列 题面 给出一个序列,求哪些元素可能在某条最长上升子序列中,哪些元素一定在所有最长上升子序列中. 题解 YJY大嫂教导我们,如果以一个元素结尾的LIS长度 + 以它 ...

随机推荐

  1. 对国外某hotel的内网域简单渗透

    Penetration Testing不单单是一个博客,更热衷于技术分享的平台. 本文将讲述对国外某一hotel的渗透测试,让更多的人安全意识得到提高,有攻才有防,防得在好,也有疏忽的地方,这就是为啥 ...

  2. vuex mapState使用

    <template> <div> {{count}} <button @click="handleIncrease">+5</button ...

  3. VueJS条件语句:v-if、v-else、v-else-if

    HTML:if-else <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  4. 转:HDMI介绍与流程

    HDMI介绍与流程   HDMI,全称为(High Definition Multimedia Interface)高清多媒体接口,主要用于传输高清音视频信号. HDMI引脚: HDMI有A,B,C, ...

  5. Spring Security 表单登录

    1. 简介 本文将重点介绍使用Spring Security登录. 本文将构建在之前简单的Spring MVC示例之上,因为这是设置Web应用程序和登录机制的必不可少的. 2. Maven 依赖 要将 ...

  6. Django之通过tag推荐文章

    #路由 views.py def post_detail(request,year,month,day,post): ''' 文章详情 + 评论详情 :param request: :param ye ...

  7. Chrome自带恐龙小游戏的源码研究(完)

    在上一篇<Chrome自带恐龙小游戏的源码研究(七)>中研究了恐龙与障碍物的碰撞检测,这一篇主要研究组成游戏的其它要素. 游戏分数记录 如图所示,分数及最高分记录显示在游戏界面的右上角,每 ...

  8. JS常见事件以及函数

    1.js enter键激发事件 document.onkeydown = function (e) {            if (!e) e = window.event;             ...

  9. java 泛型小小的测试题

    判断以下哪种书写时正确的? 1.ArrayList<String> lists = new ArrayList<String>();2.ArrayList<Object& ...

  10. python 基础 1.6 python 帮助信息及数据类型间相互转换

      一. 帮助信息   # dir() 方法  查看函数的方法   # help()   # type() 查看类型   name = raw_input('please input you name ...