HDU 1394 Minimum Inversion Number【线段树,归并排序,树状数组】
2015-11-27 22:27
453 查看
Minimum Inversion Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 15476 Accepted Submission(s): 9441
[align=left]Problem Description[/align]
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.
[align=left]Input[/align]
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.
[align=left]Output[/align]
For each case, output the minimum inversion number on a single line.
[align=left]Sample Input[/align]
10
1 3 6 9 0 8 5 7 4 2
[align=left]Sample Output[/align]
16
给出一个序列,然后每次都把最后边的数放在最前面,由此形成多个序列,求给定的一个数列形成的所有的新数列的最小逆序对数
逆序不难求得,主要是求出所有的逆序,当然进行n次线段树的操作是不可取的,所以要特殊考虑规律.....
假如 某个序列的逆序数为 s ,这个序列的最后一个元素是 am,一共n 个数,那么,在这个数的前面 有 n-am个数比am大,有 am-1个数比am 小,那么进过操作之后,逆序数会减少n-am,增加 am-1,可得,新得到的数列的逆序数为 s+n-2*am-1.....
此题用归并求逆序比较好用,因为这个题的数据比较特殊,用线段树还是比较方便的,另外还有树状数组.......
93MS
#include<stdio.h> #include<string.h> int sum[4000005],x[1000005]; int find(int rt,int l,int r,int a,int b) { if(l>=a&&r<=b) { return sum[rt]; } int mid=(l+r)>>1,tp=rt<<1,res=0; if(mid>=a) { res+=find(tp,l,mid,a,b); } if(mid<b) { res+=find(tp|1,mid+1,r,a,b); } return res; } void update(int rt,int l,int r,int p) { if(l==r) { ++sum[rt]; return; } int mid=(l+r)>>1,tp=rt<<1; if(p<=mid) { update(tp,l,mid,p); } else { update(tp|1,mid+1,r,p); } sum[rt]=sum[tp]+sum[tp|1]; } int main() { int n; while(~scanf("%d",&n)) { int cnt=0; memset(sum,0,sizeof(sum)); for(int i=0;i<n;++i) { scanf("%d",&x[i]); cnt+=find(1,0,n-1,x[i],n-1); update(1,0,n-1,x[i]); } int tp=cnt; for(int i=0;i<n;++i) { tp+=(n-2*x[i]-1); if(tp<cnt) { cnt=tp; } } printf("%d\n",cnt); } return 0; }
归并排序:(46MS)
#include<stdio.h> #include<string.h> int cnt,x[5005],t[5005]; void merge(int l,int r) { int mid=(l+r)>>1; int a=l,b=mid+1,c=l; while(a<=mid&&b<=r) { if(x[a]<=x[b]) { t[c++]=x[a++]; } else { cnt+=mid-a+1; t[c++]=x[b++]; } } while(a<=mid) { t[c++]=x[a++]; } while(b<=r) { t[c++]=x[b++]; } for(int i=l;i<=r;++i) { x[i]=t[i]; } } void sort(int l,int r) { if(l<r) { int mid=(l+r)>>1; sort(l,mid);sort(mid+1,r); merge(l,r); } } int main() { int n,y[5005]; //freopen("shuju.txt","r",stdin); while(~scanf("%d",&n)) { //memset(sum,0,sizeof(sum)); for(int i=0;i<n;++i) { scanf("%d",&x[i]); y[i]=x[i]; } cnt=0; sort(0,n-1); int tp=cnt; for(int i=0;i<n;++i) { tp+=(n-2*y[i]-1); if(tp<cnt) { cnt=tp; } } printf("%d\n",cnt); } return 0; }
用树状数组的方法有空再补上......
相关文章推荐
- LibSVM(java版)的使用
- 阿里云服务器配置php+apache+mysql+phpMyadmin开发环境并上传本地代码
- 软件性能测试的几种方法
- Linux系统内核制作和内核模块的基础
- 关于Redis的ACID
- C++笔试题
- 创建swap文件方法
- UI--手势方法介绍
- C++构造函数初始化列表 委托构造函数
- log4j
- 【成端更新线段树模板】POJ3468-A Simple Problem with Integers
- 第20章 DLL高级技术(1)
- 快速傅里叶变换算法探幽
- RHEL7 之 XFS备份与恢复
- phpstorm9安装
- Java8种基本数据类型的封装,Cache
- hdu 2063
- SQL学习笔记(2)之DDL语句
- runloop的基本使用
- runloopObserver