当前位置:网站首页>Ultra-QuickSort
Ultra-QuickSort
2022-08-04 12:36:00 【EdwinAze】
Ultra-QuickSort
题目
给一个序列,我们使用冒泡排序法对它进行排序。请输出在排序过程中会进行多少次交换。
输入包含多个测试用例
每个测试用例第一行为一个整数n(n<500000)表示数组的长度
下面n行每一行包含一个整数0≤a[i]≤999,999,999,即数组中第i个元素的值。
当n=0时结束输入
对于每个输入序列,程序打印一个数op,即对给定输入序列进行排序所需的最小交换操作数。
input
```c
5
9
1
0
5
4
3
1
2
3
0
output
6
0
思路
冒泡排序是 n 2 n^2 n2的, 这里不能用冒泡模拟, 可以试试快排和归并。
冒泡的最小交换数就是它交换的总次数, 也就说出现 后面的数大于前面的数就算一次交换。
显然这就是求逆序对的数量, 归并可以解决:
int merge_sort(int q[], int l, int r)
{
if(l >= r) return 0;
int mid = l +r >> 1;
int res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid &&j <= r)
if(a[i] <= a[j]) temp[k++] = a[i++];
else {
temp[k++] = a[j];
res += j - k;
}
while(i <= mid) temp[k++] = a[i++];
while(j <= r) temp[k++] = a[j++];
for(i; i <= r; i++) a[i] = temp[i];
return res;
}
换一种写法, 怎么用线段树来写呢?
当前数x, 后面任何一个大于x的都是逆序对, 即找在 x 后面 >= x的数 的数量。
先将输入的数组排序(这里就已经慢于归并写法, 图一乐), 然后记录原数组每个元素排序后的位置。
使用线段树的 upadate 操作依次按原数组顺序插入, 但插入的位置是排序后的位置。
即 第一个插入 9 (排序后位置pos = 5), 就插入到 [5,5], 值为该位置被插入的次数。
线段树权值记录为左右子树的和。
因为插入位置是排序后的位置, 故插入到右子树的原值肯定比插入到左子树的原值大(或者等于),所以如果插入到左子树时, 右子树有值, res就去加上右子树的值。
对于等于的情况, 可以在开始求pos时就将其化到一个位置。
如果数据范围小的话可以直接将插入的位置变成数值, 即 9 就插入到 [9,9], 省去排序操作。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 3e6 + 10;
int t[N], a[N];
int n;
vector<int> vec;
void update(int l, int r, int u, int idx, int val, long long &res)
{
if (l == r)
{
t[u]++;
return;
}
int mid = l + r >> 1;
if (idx <= mid)
{
update(l, mid, u << 1, idx, val, res);
res += t[u << 1 | 1];
}
else
update(mid + 1, r, u << 1 | 1, idx, val, res);
t[u] = t[u << 1] + t[u << 1 | 1];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> n && n != 0)
{
memset(t, 0, sizeof t);
memset(a, 0, sizeof a);
vec.clear();
for (int i = 1; i <= n; i++)
{
cin >> a[i];
vec.push_back(a[i]);
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
int pos;
long long res = 0;
for (int i = 1; i <= n; i++)
{
pos = lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin() + 1;
// cout << pos << " ";
update(1, n, 1, pos, a[i], res);
}
cout << res << endl;
}
return 0;
}
~~~
边栏推荐
猜你喜欢
小程序在政务服务平台建设中如何发挥价值
干货丨数学规划视角下的分货优化解题思路
LeetCode每日一题(858. Mirror Reflection)
如何治理资源浪费?百度云原生成本优化最佳实践
Why is Luo Zhenyu's A-share dream so difficult to fulfill?
年轻人为什么不喜欢买蒙牛、伊利了?
手搓一个“七夕限定”,用3D Engine 5分钟实现烟花绽放效果
酷开科技 × StarRocks:统一 OLAP 分析引擎,全面打造数字化的 OTT 模式
Cool and efficient data visualization big screen, it's really not that difficult to do!丨Geek Planet
什么是 DevOps?看这一篇就够了!
随机推荐
获取本机IP地址的脚本
推荐一款优秀的通用管理后台
yolo系列的head模块
第10章 模块和包
小程序对接企业微信客服
【PHP实现微信公众平台开发—基础篇】第2章 微信公众账号及申请流程详解
一分钟认识 IndexedDB 数据库,太强大了!
小程序在政务服务平台建设中如何发挥价值
考研概率论与数理统计(知识点梳理)
抽奖/秒杀/竞价/评分/权威/投票,技术教你用合适的方法做好活动
Neck modules of the yolo series
A comprehensive understanding of MOS tubes, an article is enough
聚焦数据来源、数据质量和模型性能构建小微企业信用画像
用VbScript控制光驱
罗振宇的A股梦,咋这么难圆?
使用SQLServer复制数据库
视觉SLAM十四讲学习笔记 第7讲 视觉里程计
rpm安装提示error: XXX: not an rpm package (or package manifest):
【软考 系统架构设计师】软件架构设计② 软件架构风格
MFC的相机双目标定界面设计