逆序数 POJ 2299 Ultra-QuickSort
/*
题意:就是要求冒泡排序的交换次数。
逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。
一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。
如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。也是就说,对于n个不同的元素,
先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,
当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。 接下来有多种做法求解逆序数:1. 暴力;2. 归并排序;3. 线段树-单点更新;4. 树状数组
*/
/*
暴力 超时 O(n^2)
*/
#include <stdio.h> const int MAX_N = ;
int a[MAX_N+];
long long cnt = ; int main(void) //POJ 2299 Ultra-QuickSort
{
//freopen ("inD.txt", "r", stdin);
int n; while (scanf ("%d", &n) != EOF && n)
{
for (int i=; i<=n; ++i)
{
scanf ("%d", &a[i]);
} for (int i=; i<=n; ++i)
{
for (int j=i+; j<=n; ++j)
{
if (a[i] > a[j])
cnt++;
}
}
printf ("%lld\n", cnt);
cnt = ;
} return ;
}
暴力 超时 O(n^2)
/*
归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序,
然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r),
当L[i]<=R[j]时,并不产生逆序数;
当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大,
将R[j]放在L[i]前面的话,逆序数要加上q+1-i。
因此,可以在归并排序中的合并过程中计算逆序数。 这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在:)
*/
#include <stdio.h> const int MAX_N = ;
const int INF = 0xffffff;
int a[MAX_N+];
long long cnt = ; void Merge(int *a, int p, int q, int r)
{
int n1 = q - p + ;
int n2 = r - q;
int L[MAX_N/+], R[MAX_N/+];
int i, j;
for (i=; i<=n1; ++i) L[i] = a[p+i-];
for (j=; j<=n2; ++j) R[j] = a[q+j];
L[n1+] = INF; R[n2+] = INF; i = ; j = ;
for (int k=p; k<=r; ++k)
{
if (L[i] <= R[j])
{
a[k] = L[i++];
}
else
{
a[k] = R[j++];
cnt += n1 - i + ; //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目
}
}
} void MergeSort(int *a, int p, int r)
{
int q;
if (p < r)
{
q = (p + r) / ;
MergeSort (a, p, q);
MergeSort (a, q+, r);
Merge (a, p, q, r);
}
} int main(void) //POJ 2299 Ultra-QuickSort
{
//freopen ("inD.txt", "r", stdin);
int n; while (scanf ("%d", &n) != EOF && n)
{
for (int i=; i<=n; ++i)
{
scanf ("%d", &a[i]);
}
MergeSort (a, , n);
printf ("%lld\n", cnt);
cnt = ;
} return ;
}
归并排序
/*
线段树-单点更新
*/
#include <cstdio>
#include <algorithm>
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
using namespace std; const int MAX_N = ;
const int INF = 0x3f3f3f3f;
int a[MAX_N];
int b[MAX_N];
int sum[MAX_N << ]; void pushup(int rt)
{
sum[rt] = sum[rt << ] + sum[rt << | ];
} void build(int l, int r, int rt)
{
sum[rt] = ;
if (l == r) return ;
int m = (l + r) >> ;
build (lson);
build (rson); pushup (rt);
} void update(int p, int l, int r, int rt)
{
if (l == r)
{
sum[rt]++; //记录次数
return ;
}
int m = (l + r) >> ;
if (p <= m)
{
update (p, lson);
}
else
update(p, rson);
pushup (rt);
} int query(int ql, int qr, int l, int r, int rt)
{
if (ql <= l && r <= qr)
{
return sum[rt];
}
int m = (l + r) >> ;
int ans = ;
if (ql <= m) ans += query (ql, qr, lson);
if (qr > m) ans += query (ql, qr, rson); return ans;
} int BinarySearch(int key, int l, int r)
{
while (r >= l)
{
int mid = (l + r) >> ;
if (key == b[mid]) return mid;
if (key < b[mid]) r = mid - ;
else l = mid + ;
}
} int main(void)
{
//freopen ("inD.txt", "r", stdin);
int n;
while (~scanf ("%d", &n) && n)
{
build (, n-, ); for (int i=; i<=n; ++i)
{
scanf ("%d", &a[i]);
b[i] = a[i];
}
sort (b+, b+n+);
long long ans = ;
for (int i=; i<=n; ++i)
{
int x = BinarySearch (a[i], , n);
ans += query (x, n, , n, );
update (x, , n, );
}
printf ("%lld\n", ans);
} return ;
}
线段树-单点更新
逆序数 POJ 2299 Ultra-QuickSort的更多相关文章
- 归并排序求逆序对(poj 2299)
归并排序求逆序对 题目大意 给你多个序列,让你求出每个序列中逆序对的数量. 输入:每组数据以一个数 n 开头,以下n行,每行一个数字,代表这个序列: 输出:对于输出对应该组数据的逆序对的数量: 顺便在 ...
- POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...
- poj 2299 Ultra-QuickSort (归并排序 求逆序数)
题目:http://poj.org/problem?id=2299 这个题目实际就是求逆序数,注意 long long 上白书上的模板 #include <iostream> #inclu ...
- POJ 2299 Ultra-QuickSort 归并排序、二叉排序树,求逆序数
题目链接: http://poj.org/problem?id=2299 题意就是求冒泡排序的交换次数,显然直接冒泡会超时,所以需要高效的方法求逆序数. 利用归并排序求解,内存和耗时都比较少, 但是有 ...
- poj 2299 逆序数
http://poj.org/problem?id=2299 坑:答案是long long 输出……!!!!! 题意是:求一个数组进行冒泡排序交换的次数 题解:求逆序数 题解Ⅰ: 归并排序求逆序数 归 ...
- poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)
题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...
- poj 2299 Ultra-QuickSort(树状数组求逆序数)
链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...
- poj 2299 Ultra-QuickSort 归并排序求逆序数对
题目链接: http://poj.org/problem?id=2299 题目描述: 给一个有n(n<=500000)个数的杂乱序列,问:如果用冒泡排序,把这n个数排成升序,需要交换几次? 解题 ...
- poj 2299 Ultra-QuickSort :归并排序求逆序数
点击打开链接 Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 34676 Accepted ...
随机推荐
- (7)基本工作流(使用AndroidStudio编辑Cocos项目)
接下来详细介绍一下如何使用Android Studio打开以及编辑cocos2d-x 3.10项目: 一.新建项目: 新建源代码项目,预编译库项目不支持使用Android Stduio打开,见图1 ...
- 小白科普之JavaScript的BOM模型
一.什么是BOM 1. BOM是browser object model的缩写,简称浏览器对象模型: 2. BOM提供了独立于内容而与浏览器窗口进行交互的对象,描述了与浏览器进行交互的方法和接口: 3 ...
- git参考资料
个人博客 http://www.iwangzheng.com/ $git log --graph $git reset --hard 67889898... $ssh-add $git pull -- ...
- C++中的memset()函数 ------------转自:http://www.360doc.com/content/10/1006/18/1704901_58866679.shtml
memset()函数可以对大内存的分配进行很方便的操作(初始化),所谓“初始化”,当然是指将你定义的变量或申请的空间赋予你所期望的值,例如语句int i=0;就表明定义了一个变量i,并初始化为0:如果 ...
- C#开发实例 键盘篇
键盘的操作控制: 键盘和鼠标一样是重要输入设备的一部分.开发过程中,会涉及到很多的键盘操作控制. 2.1获取键盘信息 ①获取组合键 Windows中有很多默认的组合键,如Ctrl+v,Ctrl+A.本 ...
- (转)搞ACM的你伤不起
劳资六年前开始搞ACM啊!!!!!!!!!! 从此踏上了尼玛不归路啊!!!!!!!!!!!! 谁特么跟劳资讲算法是程序设计的核心啊!!!!!! 尼玛除了面试题就没见过用算法的地方啊!!!!!! 谁再跟 ...
- Linux 的shell 字符串截取很有用。有八种方法。
一 Linux 的字符串截取很有用.有八种方法. 假设有变量 var=http://www.linuxidc.com/123.htm 1 # 号截取,删除左边字符,保留右边字符. echo ${va ...
- 【leetcode】Palindrome Partitioning
Palindrome Partitioning Given a string s, partition s such that every substring of the partition is ...
- Java for LeetCode 032 Longest Valid Parentheses
Given a string containing just the characters '(' and ')', find the length of the longest valid (wel ...
- byte[]和InputStream的相互转换[转载]
1:byte[]转换为InputStream InputStream sbs = new ByteArrayInputStream(byte[] buf); 2:InputStream转换为Input ...