Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13357 Accepted Submission(s): 8167
Problem Description
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences.
Input
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
Output
For each case, output the minimum inversion number on a single line.
Sample Input
10 1 3 6 9 0 8 5 7 4 2
Sample Output
16
//暴力求解 时间就不说了吧 #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 5000+5; int N,arr[maxn]; int main() { // freopen("input.in","r",stdin); while(~scanf("%d",&N)) { for(int i = 0;i < N;i++) { scanf("%d",&arr[i]); } int ans,cnt=0; for(int i = 0;i < N;i++) { for(int j = i+1;j < N;j++) { if(arr[i]>arr[j]) cnt++; } } ans = cnt; for(int i = 0;i < N;i++) { cnt = cnt+(N-1-arr[i])-arr[i];//找出规律,每次将最前面的数移至末尾,大于arr[i]的数为(N-1-arr[i]),小于arr[i]的数为arr[i]. ans = min(ans,cnt); } printf("%d\n",ans); } return 0; }
//树状数组:46ms
#include <map> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn = 5000+5; int N,ans,arr[maxn],TreeArr[maxn]; int lowbit(int x) { return x&(-x); } void Add(int pos,int add=1) { while(pos <= N) { TreeArr[pos] += add; pos+=lowbit(pos); } } int Sum(int pos) { int ret = 0; while(pos > 0) { ret+=TreeArr[pos]; pos -= lowbit(pos); } return ret; } int main() { //freopen("input.in","r",stdin); while(~scanf("%d",&N)) { ans = 0;memset(TreeArr,0,sizeof(TreeArr)); for(int i = 1;i <= N;i++) { scanf("%d",&arr[i]);arr[i]++; //将每个数加一,这样就把数控制在1~N范围,貌似看起来舒服些 ans += Sum(N)-Sum(arr[i]); //将之前的数中在区间arr[i]~N的个数进行累加 Add(arr[i]); } for(int i = 1,cnt = ans;i <= N;i++) { cnt += (N-arr[i])-arr[i]+1; ans = min(ans,cnt); } printf("%d\n",ans); } return 0; }
当然,我还在网上看到了有用归并排序模板过的,这里就不累赘了!转载请注明出处,谢谢!~//线段树 93ms #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn = 5000+5; int N,ans,arr[maxn],segTree[maxn<<2]; void PushUp(int rt) { segTree[rt] = segTree[rt<<1] + segTree[rt<<1|1]; } void Build(int l,int r,int rt) { segTree[rt] = 0; if(l == r) return ; int mid = l+((r-l)>>1); Build(lson); Build(rson); } void Update(int pos,int l,int r,int rt) { if(l == r) { segTree[rt]++; return ; } int mid = l+((r-l)>>1); if(pos<=mid) Update(pos,lson); else Update(pos,rson); PushUp(rt); } int Query(const int &L,const int &R,int l,int r,int rt) { if(L<=l&&r<=R) { return segTree[rt]; } int mid = l+((r-l)>>1),ret = 0; if(L<=mid) ret+=Query(L,R,lson); if(R>mid) ret+=Query(L,R,rson); return ret; } int main() { // freopen("input.in","r",stdin); while(~scanf("%d",&N)) { ans = 0;Build(1,N,1); for(int i = 0;i < N;i++) { scanf("%d",&arr[i]);arr[i]++; //将每个数加一,这样就把数控制在1~N范围,貌似看起来舒服些 if(arr[i] != N) ans += Query(arr[i]+1,N,1,N,1); //将之前的数中在区间arr[i]+1~N的个数进行累加 Update(arr[i],1,N,1); } for(int i = 0,cnt = ans;i < N;i++) { cnt += (N-arr[i])-arr[i]+1; ans = min(ans,cnt); } printf("%d\n",ans); } return 0; }