51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!
51nod 1376 最长上升子序列的数量
题解
我们设lis[i]为以位置i结尾的最长上升子序列长度,dp[i]为以位置i结尾的最长上升子序列数量。
显然,dp[i]要从前面的一些位置(设为位置j)的dp转移过来。
j要满足下面的条件:
- j < i
- a[j] < a[i]
- lis[j] = lis[i] - 1
dp[i]即为所有满足上述条件的dp[j]之和。
如果我们正常从左到右处理序列,第一条显然可以直接满足(因为大于i的位置还都没处理过)。
为了满足第三条,我们可以把lis相同的值放在一起,用vector存起来。我们设lst[i]为所有满足”lis[j] = i“的j所对应的a[j]构成的vector。
这堆vector有个性质——它是单调不减的。
为什么呢?因为这个vector中,前面的元素是序列中先出现的,后面的是序列中后出现的,而它们同在一个vector中,满足lis相同。假如后面的元素反而比前面的大,那么显然以后面的元素结尾的最长上升子序列可以从前面的元素转移过来,后面元素的lis必然比前面的要大,与它们lis相同矛盾。
那么为了满足上面的第二条条件,我们直接在vector中二分,即可求得所有满足条件的a[j]的和了,也就求出了dp[i]。
总复杂度是\(O(n \log n)\)的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <class T>
bool read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
else if(c == EOF) return 0;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
return 1;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 50005, P = 1e9+7;
int n, m, a[N], s[N], cnt;
ll dp[N];
vector <ll> lst[N], sum[N];
//lst[i]存储所有以它结尾LIS长度为i的位置上的数值,
//sum存储对应lst数组中dp值的前缀和。
ll find(int p, ll x){
//这个函数通过在lst[p]中找到最后一个>=x的数,
//从而得到所有“比x小且以它结尾的LIS长度为以x结尾的LIS长度-1”的数的dp值之和。
int l = 0, r = lst[p].end() - lst[p].begin() - 1, mid;
while(l < r){
mid = (l + r + 1) >> 1;
if(lst[p][mid] < x) r = mid - 1;
else l = mid;
}
return ((sum[p].back() - sum[p][l]) % P + P) % P;
}
int main(){
read(n);
for(int i = 1; i <= n; i++)
read(a[i]);
for(int i = 0; i <= n; i++)
lst[i].push_back(INF), sum[i].push_back(0);
lst[0].push_back(-INF), sum[0].push_back(1);
for(int i = 1; i <= n; i++){
int lis; //以位置i结尾的LIS长度
if(!cnt || a[i] > s[cnt]) s[++cnt] = a[i], lis = cnt;
else {
int pos = lower_bound(s + 1, s + cnt + 1, a[i]) - s;
s[pos] = a[i];
lis = pos;
}
lst[lis].push_back(a[i]);
sum[lis].push_back((sum[lis].back() + find(lis - 1, a[i])) % P);
}
write(sum[cnt].back()), enter;
return 0;
}
51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!的更多相关文章
- 51Nod 1376 最长递增子序列的数量 (DP+BIT)
题意:略. 析:dp[i] 表示以第 i 个数结尾的LIS的长度和数量,状态方程很好转移,先说长度 dp[i] = max { dp[j] + 1 | a[i] > a[j] && ...
- 51nod 1376 最长递增子序列的数量(线段树)
51nod 1376 最长递增子序列的数量 数组A包含N个整数(可能包含相同的值).设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递 ...
- 51Nod 1376 最长递增子序列的数量 —— LIS、线段树
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376 1376 最长递增子序列的数量 基准时间限制:1 秒 空 ...
- 51NOD 1376 最长递增子序列的数量 [CDQ分治]
1376 最长递增子序列的数量 首先可以用线段树优化$DP$做,转移时取$0...a[i]$的最大$f$值 但我要练习$CDQ$ $LIS$是二维偏序问题,偏序关系是$i<j,\ a_i< ...
- 51nod 1376 最长递增子序列的数量(不是dp哦,线段树 + 思维)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376 题解:显然这题暴力的方法很容易想到就是以每个数为结尾最 ...
- 【51nod】1376 最长递增子序列的数量
数组A包含N个整数(可能包含相同的值).设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS).A的LIS可能有很多个. ...
- 51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最 ...
- 51nod 1218 最长递增子序列 V2(dp + 思维)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1218 题解:先要确定这些点是不是属于最长递增序列然后再确定这 ...
- 51nod1376 最长递增子序列的数量
O(n2)显然超时.网上找的题解都是用奇怪的姿势写看不懂TAT.然后自己YY.要求a[i]之前最大的是多少且最大的有多少个.那么线段树维护两个值,一个是当前区间的最大值一个是当前区间最大值的数量那么我 ...
随机推荐
- 相机标定与矫正opencv+MATLAB
博客转载自:http://blog.csdn.net/Loser__Wang/article/details/51811347 本文目的在于记录如何使用MATLAB做摄像机标定,并通过opencv进行 ...
- 【SIKIA计划】_10_Unity5.1UI系统-UGUI笔记
Canvas——TextEventSystem 事件系统 0.滚动文本列表(隐藏背景)/Scroll/maskimage[Scroll Rect][Mask]——text(拉伸到显示全部)Scroll ...
- 使用过滤器解决JSP页面的乱码问题
乱码详情 总结:讨论了使用GET和POST方法,控制台和JSP页面显示的问题. 最终发现:在servlet或者过滤器中添加:request.setCharacterEncoding("ut ...
- 0.前言 three.js 简介
前言 前段时间开始接触three.js本来以为会很简单但是真正开始学习的时候才发现事情并不是我想象的那么容易,three.js的学习资料非常的少稍微好一点的资料就是收费的,给three.js的学习带来 ...
- JS如何设置元素样式的方法示例
<div id="box"></div> <script> var box = document.getElementById("bo ...
- JetBrains激活 PyCharm | IntelliJ IDEA | CLion | WebStorm...
最近,JetBrains的IDE火了起来,身为学Java的人,放弃了Eclipse,选择了Idea,还真有点不舍得呢... 虽然Idea不错(在我看来,比Eclipse好用),但是,人家是收费的呀.. ...
- php从入门到放弃系列-01.php环境的搭建
php从入门到放弃系列-01.php环境的搭建 一.为什么要学习php 1.php语言适用于中小型网站的快速开发: 2.并且有非常成熟的开源框架,例如yii,thinkphp等: 3.几乎全部的CMS ...
- linux安装nginx并配置负载均衡
linux上安装nginx比较简单: 前提是需要有gcc或者g++ 1.yum需要的依赖 yum -y install openssl openssl-devel 2.解压pcre库.zlib库 ...
- spring boot之配置跨域
在启动类中配置 @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override p ...
- 20162319 实验二 Java面对对象程序设计 实验报告
实验二 Java面向对象程序设计 实验内容 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握UML建模 4.熟悉S.O.L.I.D原则 5.了解设计模式 实验 ...