POJ 2299
发布日期:2021-06-30 15:31:07 浏览次数:2 分类:技术文章

本文共 3519 字,大约阅读时间需要 11 分钟。

Ultra-QuickSort

Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 72150   Accepted: 27104

Description

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence

9 1 0 5 4 ,

Ultra-QuickSort produces the output 

0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

59105431230

Sample Output

60

Source

 

大致题意:

给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。

解题思路:

跟POJ1804要求一样,区别是这个数组的范围最大为50W

所以之前使用的冒泡方法O(n^2),复杂度铁定超肯定是会超时的。

直接用快排又不符合题目的要求(相邻元素交换),快排是建立在二分的基础上的,

操作次数肯定比在所要求的规则下的交换次数要更少 那么该怎么处理?

其实这题题目已经给出提示了:

Ultra-QuickSort 特殊的快排,能和快排Quicksort相媲美的就是归并排序Mergesort了,

O(nlogn) 但是用归并排序并不是为了求交换次数,而是为了求序列的 逆序数

一个乱序序列的 逆序数 = 在只允许相邻两个元素交换的条件下, 得到有序序列的交换次数

代码:

#include
#include
#include
#define ll long long#define MAX 2147483647#define fi first#define se second#define fo(i,a,b) for(int i=(a);i<=(b);++i)#define fodown(i,a,b) for(int i=(a);i>=(b);i--)using namespace std;int n,a[500005],b[5000005];ll ans;int read(){ int x=0,tmp=1; char ch=getchar(); while(ch<'0' || ch>'9' ) { if(ch=='-') tmp=-1;ch=getchar();} while(ch>='0'&& ch<='9') { x = x * 10+ ch-'0';ch=getchar();} return x*tmp;}void merge(int l,int m,int r){ int i=l,j=m+1,tot=l-1; while(i<=m&&j<=r) { if(a[i]<=a[j]) b[++tot]=a[i],i++; else { b[++tot]=a[j]; ans+=m-i+1;/*我们能保证(l,m)这个区间是升序的,这是显然的,因为先排序这个区间,再排序整个区间,如果a[j]
>1; qsort(l,mid);//分块 qsort(mid+1,r); merge(l,mid,r);}int main(){ // freopen(" .in","r",stdin); // freopen(" .out","w",stdout); while(scanf("%d",&n)!=EOF&&n) { fo(i,1,n) a[i]=read(); ans=0; qsort(1,n); cout<
<

其实还有另一种高大上的求法:树状数组

具体理解:

# define Name ""# include 
# include
# include
# include
# define LL long longusing namespace std ;const int N = 5e5 + 10 ;int a [N] , b [N] , c [N] , n ;int lowbit ( int x ) { return ( - x ) & x ;}void modify ( int pos , int val ) { for ( int i = pos ; i <= n ; i += lowbit ( i ) ) c [i] += val ;}int query ( int pos ) { int ret = 0 ; for ( int i = pos ; i >= 1 ; i -= lowbit ( i ) ) ret += c [i] ; return ret ;}int main () { while ( scanf ( "%d" , & n ) != EOF && n ) { memset ( c , 0 , sizeof c ) ; for ( int i = 1 ; i <= n ; ++ i ) scanf ( "%d" , & a [i] ) , b [i] = a [i] ; sort ( a + 1 , a + 1 + n ) ; for ( int i = 1 ; i <= n ; ++ i ) b [i] = lower_bound ( a + 1 , a + 1 + n , b [i] ) - a ; LL ans = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { modify ( b [i] , 1 ) ; ans += i - query ( b [i] ) ; } printf ( "%lld\n" , ans ) ; } return 0 ;}

 

 

转载地址:https://joycez.blog.csdn.net/article/details/83096932 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:POJ 3349
下一篇:POJ 1936

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月29日 03时59分36秒