Hdu 1394 Minimum Inversion Number、Poj 2299 Ultra-QuickSort
2013-06-06 23:00
489 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
题意:求某种规定序列中的最小逆序数。
递推比较最小那部分比较简单,就不说了。
主要想说:求逆序数可以用构建线段树的方法来做。其实思想和计数排序的思想差不多。每次处理a[i]时,先统计一下已经被计数的前几个数的计数和。(比较的是值。)然后再更新这个计数和。这道题的数据范围和下标范围是一样的,所以可以直接做。
详见代码:
但是如果数据范围和下标范围不是一个范围的话,我们就不能直接用这个方法 做了。。试想,如果一个数有最大可以有十亿,难道我们要开一个十亿大小的数组来标记么。。这显然不现实。所以我们要对数据进行离散话,毕竟数据的数量达不到那么大。比如说这道题:http://poj.org/problem?id=2299。也是求逆序数。数据的范围特别大。但是数量比较少。非常适合离散化。
关于什么是离散话,参考:http://www.matrix67.com/blog/archives/108 和 http://baike.baidu.com/view/3392254.htm
那么离散化+线段树我们就可以做这道题了(不要忘了用long long,int存储不下最终结果):
另外,求逆序数也可以用树状数组和归并排序来做。
用线段树属于平衡树做法的一种。
题意:求某种规定序列中的最小逆序数。
递推比较最小那部分比较简单,就不说了。
主要想说:求逆序数可以用构建线段树的方法来做。其实思想和计数排序的思想差不多。每次处理a[i]时,先统计一下已经被计数的前几个数的计数和。(比较的是值。)然后再更新这个计数和。这道题的数据范围和下标范围是一样的,所以可以直接做。
详见代码:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <map> #include <queue> #include <algorithm> using namespace std; #define Maxn 5005 #define lx x<<1 #define rx ((x<<1) + 1) #define MID ((l + r)>>1) int A[Maxn]; int S[Maxn<<2]; void pushUp(int x) { S[x] = S[lx] + S[rx]; } void build(int l,int r,int x) { if(l == r) { S[x] = 0; return; } build(l,MID,lx); build(MID+1,r,rx); pushUp(x); } int query(int L,int R,int l,int r,int x) { int ans = 0; if(L<=l && r<=R) return S[x]; if(L<=MID) ans += query(L,R,l,MID,lx); if(R>=MID+1) ans += query(L,R,MID+1,r,rx); return ans; } void update(int p,int d,int l,int r,int x) { if(l == r) { S[x] +=d; return; } if(p<=MID) update(p,d,l,MID,lx); else update(p,d,MID+1,r,rx); pushUp(x); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int n; int sum,ans,temp; while(scanf(" %d",&n)!=EOF) { sum = ans = 0; build(0,n-1,1); for(int i=0;i<n;i++) { scanf(" %d",&A[i]); temp = query(A[i],n-1,0,n-1,1); sum += temp; update(A[i],1,0,n-1,1); } ans = sum; //递推求解,每次A[i]都在首位,则分为大于它的部分和小于它的部分。 for(int i=0;i<n;i++) { sum += n-1-A[i] - A[i]; ans = min(ans,sum); } printf("%d\n",ans); } return 0; }
但是如果数据范围和下标范围不是一个范围的话,我们就不能直接用这个方法 做了。。试想,如果一个数有最大可以有十亿,难道我们要开一个十亿大小的数组来标记么。。这显然不现实。所以我们要对数据进行离散话,毕竟数据的数量达不到那么大。比如说这道题:http://poj.org/problem?id=2299。也是求逆序数。数据的范围特别大。但是数量比较少。非常适合离散化。
关于什么是离散话,参考:http://www.matrix67.com/blog/archives/108 和 http://baike.baidu.com/view/3392254.htm
那么离散化+线段树我们就可以做这道题了(不要忘了用long long,int存储不下最终结果):
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <map> #include <queue> #include <algorithm> using namespace std; #define Maxn 500005 #define lx x<<1 #define rx ((x<<1) + 1) #define MID ((l + r)>>1) #define LL long long int rank[Maxn]; LL S[Maxn<<2]; struct Node { int val; int id; bool operator <(const Node &a) const { return val < a.val; } } A[Maxn]; void pushUp(int x) { S[x] = S[lx] + S[rx]; } void build(int l,int r,int x) { if(l == r) { S[x] = 0; return; } build(l,MID,lx); build(MID+1,r,rx); pushUp(x); } LL query(int L,int R,int l,int r,int x) { LL ans = 0; if(L<=l && r<=R) return S[x]; if(L<=MID) ans += query(L,R,l,MID,lx); if(R>=MID+1) ans += query(L,R,MID+1,r,rx); return ans; } void update(int p,int d,int l,int r,int x) { if(l == r) { S[x] +=d; return; } if(p<=MID) update(p,d,l,MID,lx); else update(p,d,MID+1,r,rx); pushUp(x); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int n; LL ans = 0; int temp; while(scanf(" %d",&n)!=EOF) { ans = 0; if(n == 0) break; build(0,n-1,1); for(int i=0;i<n;i++) { scanf(" %d",&A[i].val); A[i].id = i; } sort(A,A+n); for(int i=0;i<n;i++) rank[A[i].id] = i; for(int i=0;i<n;i++) { temp = rank[i]; ans += query(temp+1,n-1,0,n-1,1); update(temp,1,0,n-1,1); } printf("%lld\n",ans); } return 0; }
另外,求逆序数也可以用树状数组和归并排序来做。
用线段树属于平衡树做法的一种。
相关文章推荐
- Hdu 1394 Minimum Inversion Number、Poj 2299 Ultra-QuickSort
- hdu 1394 Minimum Inversion Number 线段树求逆序数
- Minimum Inversion Number HDU 1394
- hdu 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number (最小逆序对数&线段树)
- HDU 1394 Minimum Inversion Number(线段树 || 树状数组+逆序数 )
- hdu1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number
- HDU 1394 Minimum Inversion Number (数据结构-线段树)
- HDU 1394 Minimum Inversion Number (离散化 + 树状数组 求逆序对)
- 【HDU】1394 Minimum Inversion Number
- poj1394——Minimum Inversion Number——————【线段树单点更新、逆序数特性】
- hdu 1394 Minimum Inversion Number(树状数组)
- HDU - 1394 _Minimum Inversion Number(归并排序求逆序数)
- [HDU 1394] Minimum Inversion Number 逆序对
- HDU 1394 Minimum Inversion Number (BIT入门)
- HDU 1394 & ZOJ 1484 Minimum Inversion Number
- HDU 1394 Minimum Inversion NumberMinimum Inversion Number(线段树)