逆序对数列(DP+前缀和)
又是DP又是前缀和,小白做题太慢了/(ㄒoㄒ)/~~
洛谷P2513,Acwing2692
题目
对于一个数列 {ai},如果有 i<j 且 ai>aj,那么我们称 ai 与 aj 为一对逆序对数。
若对于任意一个由 1∼n 自然数组成的数列,可以很容易求出有多少个逆序对数。
那么逆序对数为 k 的这样自然数数列到底有多少个?
输入输出
输入:共一行,两个整数 n,k。
输出:输出一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对 10000 求余数后的结果。
思路
求1-n的全排列中逆序对数为k的排序,可用动态规划来做。
动态规划数组:dp[i][j]
(0 <= j <= k)为1-i个数的全排列中逆序对数为j的方案数。
可以由1-(i-1)得出的结果来推断 1-i的结果
将i插入1-(i-1)的排列中,会增加逆序对
动态规划的初始化结果为dp[i][0] = 1
考虑i放置的位置,放i-1个位置都能增加逆序对数量
当i插在1-(i-1)的排列最后一个位置时,没有增加逆序对数,dp[i][j] += dp[i-1][j]
当i插在1-(i-1)的排列倒数第二个位置时,增加了一个逆序对数,dp[i][j] += dp[i-1][j-1]
......
当i插在1-(i-1)的排列倒数第m个位置时,增加了m-1个逆序对数,dp[i][j] += dp[i-1][j-m+1]
......
当i插在1-(i-1)的排列倒数第j+1个位置时,增加了j个逆序对数,dp[i][j] += dp[i-1][0]
注意:i最多能在1-(i-1)的序列上贡献i-1个逆序对
当j>=i-1时,dp[i][j]不能加上 dp[i-1][0-(j-i+1]这一段
时间复杂度:不经任何优化的时间复杂度是O(n^3),会超时
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int dp[N][N];
int main()
{
int n,k;
cin >> n >> k;
for (int i = 1; i <= n; i ++ ) dp[i][0] = 1;
for (int i = 2; i <= n; i ++ ){ //枚举n个数
for(int j = 1;j <= k;j ++){ //枚举逆序对的个数
for(int m = max(0,j-i+1);m <=j;m++){
dp[i][j] = (dp[i][j] + dp[i-1][m])%10000;
}
}
}
cout << dp[n][k];
}
用前缀和优化
上述算法时间复杂度:不经任何优化的时间复杂度是O(n^3),会超时
用sum记录dp[i-1][j],前j个之和,并当j>=i-1时,sum减去dp[i-1][j-i+1],相当于上面那种算法,没有把dp[i-1][0-(j-i+1]这一段算进去。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int dp[N][N];
int main()
{
int n,k;
cin >> n >> k;
for (int i = 1; i <= n; i ++ ) dp[i][0] = 1;
for (int i = 2; i <= n; i ++ ){ //枚举n个数
int sum = 0;
for(int j = 0;j <= k;j ++){ //枚举逆序对的个数
sum = (sum + dp[i-1][j]) % 10000;
dp[i][j] = sum;
if(j >= i - 1)
sum = (sum - dp[i-1][j-i+1] + 10000) % 10000;
}
}
cout << dp[n][k];
}
原文地址:https://www.cnblogs.com/Hfolsvh/p/15034198.html
- 转-- Golang中timer定时器实现原理
- Golang语言 -并行程序
- 深度学习中的优化问题以及常用优化算法
- GoldenGate简单复制环境的搭建(r10笔记第79天)
- 在Golang语言中统计程序执行时间
- 经典面试问题: Top K 之 ---- 海量数据找出现次数最多或,不重复的。
- 每天一个Linux命令(2):cd命令
- Golang语言为类型添加方法
- 浅谈 Glide - BitmapPool 的存储时机 & 解答 ViewTarget 在同一View显示不同的图片时,总用同一个 Bitmap 引用的原因
- 100个Numpy练习【2】
- 浅谈 maxMemory , totalMemory , freeMemory 和 OOM 与 native Heap
- 100个Numpy练习【1】
- XGoServer 一个基础性、模块完整且安全可靠的服务端框架
- Bing 每日一图 & 随机图片 API
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 简述PHP7.4 新特性和废弃的功能
- laravel5.1框架下的批量赋值实现方法分析
- Laravel框架环境与配置操作实例分析
- 记Laravel调用Gin接口调用formData上传文件的实现方法
- Laravel框架视图和模型操作方法分析
- 接口测试框架实战(六) | 配置的数据驱动
- PHP连续签到功能实现方法详解
- PHP实现发送微博消息功能完整示例
- php实现快速对二维数组某一列进行组装的方法小结
- PHP实现提取多维数组指定一列的方法总结
- PHP实现二维数组(或多维数组)转换成一维数组的常见方法总结
- Laravel框架Eloquent ORM简介、模型建立及查询数据操作详解
- Laravel框架下载,安装及路由操作图文详解
- PHP实用小技巧之调用录像的方法
- Laravel重定向,a链接跳转,控制器跳转示例