HDU 1394 Minimum Inversion Number【线段树&&归并排序】
来源:互联网 发布:社交软件 日语 编辑:程序博客网 时间:2024/06/09 16:47
Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 15156 Accepted Submission(s): 9253
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
101 3 6 9 0 8 5 7 4 2
Sample Output
16
题目大意就是说,首先,逆序数就是ai > aj , i < j ,这样的情况。然后题意就是说给一数列,然后每次把第一个数移到最后可以得到一个新的数列,这样n个数的数列可得到n个数列,问这n个数列中最小的逆序对数。
然后是求逆序对数,但不用每个数列都求,求出一个之后,设第一个数为x,则数列后有x个数比它小,n-x-1个数比它大,现在把x放到最后则x之前有n-x-1个数比它大,所以此时的逆序对数就是之前求得的减去x(开始x后的x个比它小的数现在没有了)再加上n-x-1(之前x前没有比它大的数,现在有n-x-1个比它大的数,所以加上)。
这里用线段树求逆序数的话,每次找出序列中最大的元素放到它本来的位置,然后看此时该位置之前有没有比它大的数,有几个,逆序数就相应加几。所以这里要用结构体记录值和位置,值用来排序求逆序数,位置用来恢复原来顺序,求最小逆序数。
#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>#define maxn 5000+10using namespace std;int sum[maxn<<2];struct lnode{ int v,p;};lnode rec[maxn];int cmp1(lnode a,lnode b){ return a.v>b.v;}int cmp2(lnode a,lnode b){ return a.p<b.p;}void pushup(int o){ sum[o]=sum[o<<1]+sum[o<<1|1];}void build(int o,int l,int r){ sum[o]=0; if(l==r) return ; int mid=(l+r)>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r); pushup(o);}void update(int o,int l,int r,int aim){ if(l==r) { sum[o]++; return ; } int mid=(l+r)>>1; if(aim<=mid) update(o<<1,l,mid,aim); else update(o<<1|1,mid+1,r,aim); pushup(o);}int query(int o,int l,int r,int a,int b){ if(a<=l&&b>=r) { return sum[o]; } int mid=(l+r)>>1; int ans=0; if(b<=mid) ans+=query(o<<1,l,mid,a,b); else if(a>mid) ans+=query(o<<1|1,mid+1,r,a,b); else { ans+=query(o<<1,l,mid,a,mid); ans+=query(o<<1|1,mid+1,r,mid+1,b); } return ans;}int main(){ int n; while(~scanf("%d",&n)) { int tem=0,cnt=0; build(1,1,n); for(int i=0;i<n;++i) { scanf("%d",&rec[i].v); rec[i].p=i+1; } sort(rec,rec+n,cmp1); for(int i=0;i<n;++i) { update(1,1,n,rec[i].p); if(rec[i].p!=1) cnt+=query(1,1,n,1,rec[i].p-1); } sort(rec,rec+n,cmp2); tem=cnt; for(int i=0;i<n;++i) { tem+=n-1-rec[i].v-rec[i].v; cnt=cnt<tem?cnt:tem; } printf("%d\n",cnt); } return 0;}
这里归并排序就不说了。之前做的归并排序的题有解释
#include<cstdio>#include<cstring>#define maxn 5000+10int cnt,a[maxn];int b[maxn],p[maxn];void Merge(int left,int mid,int right){ int n=mid,m=right; int i=left,j=mid+1; int k=0; while(i<=n&&j<=m) { if(a[i]<=a[j]) p[k++]=a[i++]; else { p[k++]=a[j++]; cnt+=n-i+1; } } while(i<=n) p[k++]=a[i++]; while(j<=m) p[k++]=a[j++]; for(int i=0;i<k;++i) a[left+i]=p[i];}void mergesort(int left,int right){ if(left<right) { int mid=(left+right)>>1; mergesort(left,mid); mergesort(mid+1,right); Merge(left,mid,right); }}int main(){ int n; while(~scanf("%d",&n)) { cnt=0; for(int i=0;i<n;++i) { scanf("%d",&a[i]); b[i]=a[i]; } mergesort(0,n-1); int mini=cnt; for(int i=0;i<n;++i) { cnt+=n-b[i]-1-b[i]; mini=mini<cnt?mini:cnt; } printf("%d\n",mini); } return 0;}
0 0
- 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(线段树/归并排序求逆序对数)
- 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 线段树
- hdu 1394 Minimum Inversion Number 线段树
- hdu 1394 Minimum Inversion Number 线段树
- TextField和TextView 的一些不同点
- Animate.css动画演示 (很棒)
- MyBatis注解Annotation介绍及Demo
- Notepad++常用命令大全
- iOS抽奖转盘动画之CAKeyFrame关键帧动画
- HDU 1394 Minimum Inversion Number【线段树&&归并排序】
- CURL GITLAB API
- BC LCS
- 复选按钮全选
- ectouch 最新版的调试方式 。。ectouch很容易出现 404 错误 因为他是thinkphp写的
- varnishd安装与配置
- web提示问题
- codeforces 324# C. Marina and Vasya (贪心)
- 在代码中设置文字的大小,可以指定单位