51Nod 1376 最长递增子序列的数量(dp+树状数组)

2024-04-20 12:18

本文主要是介绍51Nod 1376 最长递增子序列的数量(dp+树状数组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接

最长递增子序列的题做过不少,让求数量的还是第一次,O(n^2)的代码很好写,但数据范围50000,故无情超时,想了很久,总算有所得。

时间: O(nlog(n)) 空间: O(2*n)

思路
O(n^2)的思路中,每次求以第i个数结尾的最大长度和记录总数都要对前i-1个数进行遍历比较,如果能把这个比较过程转化为对前i项对求和,就可以用树状数组或线段数进行求和优化了。

    重载+,按照题目需求重新定义求和意义Node operator + (const Node &t) const{if(this->len < t.len)return t;if(this->len > t.len)return (*this);return Node(t.len, (this->cnt + t.cnt) % MOD);

于是有 dp(i) = sum(dp(0, i-1)) + 1;
为什么可以这样呢。我们对序列的数从小到大进行操作,当前数的值等于原有顺序下前面所有数的求和,因为前面比它大的数都还为0尚未更新,不会造成影响,而已更新的数都是比它小的,所以它的值就是前面的求和结果再加1。

代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;const int MAX = 50005;
const int MOD = 1000000007;struct Node
{int len, cnt;Node(){}Node(int len, int cnt): len(len), cnt(cnt){}Node operator + (const Node &t) const{if(this->len < t.len)return t;if(this->len > t.len)return (*this);return Node(t.len, (this->cnt + t.cnt) % MOD);}
};struct Num
{int num, pos;
};Node c[MAX];
Num d[MAX];bool cmp(Num &a, Num &b)
{if(a.num == b.num)return a.pos > b.pos;return a.num < b.num;
}void update(Node a,int pos, int n)
{for(int i = pos; i <= n; i += i&(-i))c[i] = c[i] + a;
}Node query(int pos)
{Node ans(0, 0);for(int i = pos-1; i > 0; i -= i&(-i))ans = ans + c[i];return ans;
}int main()
{int n;scanf("%d", &n);for(int i = 0; i < n; ++i){scanf("%d", &d[i].num);d[i].pos = i+1;}sort(d, d+n, cmp);Node ans(0, 0);for(int i = 0; i < n; ++i){Node t = query(d[i].pos);if(++t.len == 1) t.cnt = 1;ans = ans + t;update(t, d[i].pos, n);}printf("%d\n", ans.cnt);return 0;
}

这篇关于51Nod 1376 最长递增子序列的数量(dp+树状数组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/920238

相关文章

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

利用Python实现时间序列动量策略

《利用Python实现时间序列动量策略》时间序列动量策略作为量化交易领域中最为持久且被深入研究的策略类型之一,其核心理念相对简明:对于显示上升趋势的资产建立多头头寸,对于呈现下降趋势的资产建立空头头寸... 目录引言传统策略面临的风险管理挑战波动率调整机制:实现风险标准化策略实施的技术细节波动率调整的战略价

JAVA数组中五种常见排序方法整理汇总

《JAVA数组中五种常见排序方法整理汇总》本文给大家分享五种常用的Java数组排序方法整理,每种方法结合示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录前言:法一:Arrays.sort()法二:冒泡排序法三:选择排序法四:反转排序法五:直接插入排序前言:几种常用的Java数组排序

MySQL精准控制Binlog日志数量的三种方案

《MySQL精准控制Binlog日志数量的三种方案》作为数据库管理员,你是否经常为服务器磁盘爆满而抓狂?Binlog就像数据库的“黑匣子”,默默记录着每一次数据变动,但若放任不管,几天内这些日志文件就... 目录 一招修改配置文件:永久生效的控制术1.定位my.cnf文件2.添加核心参数不重启热更新:高手应

PostgreSQL 序列(Sequence) 与 Oracle 序列对比差异分析

《PostgreSQL序列(Sequence)与Oracle序列对比差异分析》PostgreSQL和Oracle都提供了序列(Sequence)功能,但在实现细节和使用方式上存在一些重要差异,... 目录PostgreSQL 序列(Sequence) 与 oracle 序列对比一 基本语法对比1.1 创建序

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.