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

相关文章

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

力扣SQL50 每位经理的下属员工数量 join

Problem: 1731. 每位经理的下属员工数量 👨‍🏫 参考题解 Code select m.Employee_id, m.name,count(*) reports_count,round(avg(e.age),0) average_agefrom Employees ejoin Employees mon e.reports_to = m.Employee_id

剑指offer(C++)--数组中只出现一次的数字

题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 class Solution {public:void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {int len = data.size();if(len<2)return;int one = 0;for(int i

IOS 数组去重的几种方式

本来只知道NSSet和KeyValues的。今天又新学了几种方式 还有就是和同事学的一种方式 外层循环从0开始遍历,内层从最后一个元素开始遍历 for(int i=0;i<index;i++){  for(int j=index-1;j>i;j-- ){ } }

代码随想录——摆动序列(Leetcode376)

题目链接 贪心 class Solution {public int wiggleMaxLength(int[] nums) {if(nums.length <= 1){return nums.length;}// 当前一对差值int cur = 0;// 前一对差值int pre = 0;// 峰值个数int res = 1;for(int i = 0; i < nums.length -

想让Python序列切片更高效?这些技巧你不可不知!

目录 1、自定义类实现切片 🍏 1.1 实现__getitem__方法 1.2 支持正负索引与步长 2、利用 collections.abc 模块 🧠 2.1 继承MutableSequence类 2.2 重写关键方法 3、使用标准库itertools.slice 🍲 3.1 itertools工具介绍 3.2 slice函数应用实例 4、通过生成器实现动态切片 🌀

Java基础(二)——数组,方法,方法重载

个人简介 👀个人主页: 前端杂货铺 ⚡开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL) 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步至千里,积小流成江海 🥇推荐学习:🍖开源 rich-vue3 🍍前端面试

上海邀请赛 A题目 HDU 5236(dp)

先求出没有ctrl+s的时候构造长度为i的期望f[i] 。然后枚举保存的次数,求出最小即可。 #include<cstdio>#include<cstdio>#include<cmath>#include<queue>#include<stack>#include<string>#include<cstring>#include<iostream>#include<map>

poj 3882(Stammering Aliens) 后缀数组 或者 hash

后缀数组:  构建后缀数组,注意要在字符串莫末尾加上一个没出现过的字符。然后可以2分或者直接扫描,直接扫描需要用单调队列来维护 VIEW CODE #include<cstdio>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#include<stack>#include<string

poj 3294(Life Forms) 2分+ 后缀数组

我曾用字符串hash写,但是超时了。只能用后最数组了。大致思路:用不同的符号吧字符串连接起来,构建后缀数组,然后2分答案,依次扫描后缀数组,看是否瞒住条件。 VIEW CODE #include<cstdio>#include<vector>#include<cmath>#include<algorithm>#include<cstring>#include<cassert>#