POJ 2299 Ultra-QuickSort (树状数组、归并排序)
来源:互联网 发布:农村淘宝 app 下载 编辑:程序博客网 时间:2024/06/18 09:03
题目链接:http://poj.org/problem?id=2299
做法一:归并排序求逆序对
归并排序求逆序对的做法很经典,在归并排序中,如果 left<=i<=mid 和 mid+1 <=j<=right,(i<j) ,那么,如果 a[i]<=a[j],这并不产生逆序对,但是,如果a[i]>a[j],如果在mid之前有大于k个大于a[j]的数,那么ans+=k,k是多少呢?k=mid-i+1!为什么?你想想,因为a[i]>a[j],因为 i~~mid已经排序好了,就是说a[i]<a[i+1]<a[i+2]<....<a[mid],就是说i~mid的数都可以与j形成逆序对,证明完毕,k=mid-i+1。在每次合并的时候 ,如果a[i]>a[j],ans+=k即可。
贴上渣渣代码:
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <stack>#include <queue>#include <cstring>#include <map>#include <set>#define LL long long#define pb push_back#define pf push_front#define loop(a,b,c) for(int a=b;a<=c;a++)#define rloop(a,b,c) for(int a=b;a>=c;a--)#define clr(a,b) memset(a,b,sizeof a)#define inf 1<<30#define x first#define y second#define maxn 500005using namespace std;int a[maxn],n;LL ans;void merge(int l,int r){int *b = new int[maxn];int m = (l+r)/2,i,j,len=0;i=l;j=m+1;while(i<=m&&j<=r){if(a[i]<=a[j]) b[len++] = a[i++];else b[len++] = a[j++],ans+=m-i+1;}while(i<=m) b[len++] = a[i++];while(j<=r) b[len++] = a[j++];loop(i,0,len-1) a[l+i] = b[i]; delete []b;}void merge_sort(int l,int r){if(l>=r) return;int m = (l+r)/2;merge_sort(l,m);merge_sort(m+1,r);merge(l,r);}void solve(){loop(i,1,n)scanf("%d",&a[i]);ans=0;merge_sort(1,n);printf("%lld\n",ans);}int main(){//freopen("data.txt","r",stdin);while(scanf("%d",&n)&&n)solve();}
额,跑了1069MS
做法二:树状数组
当我听说可以用树状数组做的时候,确实有点摸不着头脑。。。完全没想到可以用树状数组去做(怪我渣咯)
怎么做呢?其实原理很简单!就取样例来说吧!
对于样例 n=5 ,a[1~n] = {9,1,0,5,4},不妨设d[j]表示 j 是否出现过,若是,标记为1
当i=1,d[9]=1,对0~9求和,即sum(9)=1,说明了有多少个数是不大于9的,那么i-sum(a[i])就表示有多少个数比a[i] 大了,在这里就是1-sum(9)=0
当i=2,d[1]=1,对0~1求和,sum(1)=1,那么在i=0~2就有2-sum(1)=1个数比2大
当i=3,d[0]=1,对0~0求和,sum(0)=1,那么在i=0~3就有3-sum(0)=2个数比1大
以此类推。。。
将上面的i-sum(a[i])加起来,就是答案了
但是,题目所给的数范围是0~999,999,999,根本没办法开一个d数组那么大!但是,观察到n最大才500,000,其实每个a[i]都可以映射成1~~500,000的每个数!
简而言之,就是要对数组进行离散化!
还是对于样例n=5 ,a[1~n] = {9,1,0,5,4},我们用一个结构体(或者pair)来记录原输入的值大小以及它的下标,对于样例而言,就是
{(x,y)|(9,1),(1,2),(0,3),(5,4),(4,5),x是输入的值,y是下标}
对上面按x值大小排序得
{(x,y)|(0,3),(1,2),(4,5),(5,4),(9,1),x是输入的值,y是下标}
用一个b数组来存储离散化后的数组,即有b[x[i]]=i !!结果为 {5,2,1,4,3}
为什么要这样做呢?一开始我也有点懵逼,毕竟我是第一次接触离散化这个东西。
但是,只要认真想想就知道, 其实就是改变了x的值,把x的范围缩减到1~500,000的范围,然后变回原来的顺序而已。可以看出离散化后,数组中所有元素的大小关系是完全没有变化的!
然后我们就可以开一个足够大的数组去实现之前的算法了!
贴上代码:
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <stack>#include <queue>#include <cstring>#include <map>#include <set>#define LL long long#define pb push_back#define pf push_front#define loop(a,b,c) for(int a=b;a<=c;a++)#define rloop(a,b,c) for(int a=b;a>=c;a--)#define clr(a,b) memset(a,b,sizeof a)#define inf 1<<30#define x first#define y second#define maxn 500005using namespace std;typedef pair<int,int> P;int n,ans,c[maxn],d[maxn];P a[maxn];int lowbit(int x) {return x&(-x);}void updata(int i,int x){while(i<=n){c[i]+=x;i += lowbit(i);}}int sum(int i){int s = 0;while(i>0){s += c[i];i -= lowbit(i);}return s;}void solve(){loop(i,1,n)scanf("%d",&a[i].x),a[i].y=i;ans = 0;sort(a[i]+1,a[i]+n+1);loop(i,1,n) d[i]=a[i].y;// loop(i,1,n) printf("%d\n",d[i]);loop(i,1,n){updata(d[i],1);ans+=i-sum(d[i]);}printf("%d\n",ans);}int main(){//freopen("data.txt","r",stdin);while(scanf("%d",&n)&&n)solve();}
运行了422MS,按道理说呢时间复杂度都是nlogn的,不过实际运行起来,相差还是蛮大的,难道跟归并排序的递归有关?
- POJ 2299 Ultra-QuickSort (树状数组、归并排序)
- POJ:2299 Ultra-QuickSort(归并排序/树状数组)
- POJ 2299 Ultra-QuickSort 树状数组,归并排序
- poj 2299 Ultra-QuickSort(树状数组-改上求下+改下求上||归并排序)
- POJ 2299 Ultra QuickSort <树状数组+离散化 / 归并排序>
- poj 2299 Ultra-QuickSort(归并排序)||(树状数组+离散化)
- POJ 2299 Ultra-QuickSort 求逆序对数(归并排序,树状数组)
- Ultra-QuickSort (poj 2299 归并排序 || 树状数组 求逆序对)
- POJ 2299 Ultra-QuickSort(逆序对数,线段树/树状数组/归并排序)
- POJ 2299 Ultra-QuickSort(归并排序 || 树状数组 || 线段树)
- POJ 2299 Ultra-QuickSort(归并排序,树状数组,离散化)
- POJ Ultra-QuickSort 逆序数 树状数组 归并排序
- POJ 2299 Ultra-QuickSort(归并排序)
- POJ - 2299 Ultra-QuickSort (归并排序)
- POJ 2299 Ultra-QuickSort (归并排序)
- POJ 2299 Ultra-QuickSort(归并排序)
- POJ 2299 Ultra-QuickSort (归并排序)
- poj - 2299 - Ultra-QuickSort(树状数组)
- 数组名 和 &数组名
- nyoj 733 万圣节派对
- iOS和JS的交互之在代理方法拦截Url,识别判断
- 枚举ssdt 地址表
- 机器学习(周志华) 参考答案 第五章 神经网络 5.5
- POJ 2299 Ultra-QuickSort (树状数组、归并排序)
- actor model && Big Data
- SVN中增加所有新增文件
- iOS开发----IOS项目自动生成技术文档
- 机器学习(周志华) 参考答案 第五章 神经网络 5.7
- 读《精通JavaScript+jQuery》笔记三
- CABasicAnimation animationWithKeyPath 一些规定的值
- IntelliJ IDEA 14.x 创建工作空间与多个Java Web项目
- 图像二值化方法--OTSU(最大类间方差法)