hdu1394 Minimum Inversion Number(线段树单点修改+区间求和)
2017-09-15 20:30
573 查看
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.
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
大致题意:给你一个0到n-1这n个数所组成的序列,然后每次将第一个数放到最后一个位置上,得到一个新的序列,总共有n个序列,然你求出这n种情况的最少逆序数。
思路:先考虑如何去求一个序列的逆序数,如果暴力去求的话时间复杂度为n^2,这里我们用线段树来做,每次新加入一个数A[i]时,我们可以在logn的时间内统计此时出A[i]+1到n-1的范围内出现的数的次数,即前i-1个数中有多少个数大于A[i],然后修改A[i]的次数加一。这样总的时间复杂度就降到了nlogn。
然后得到初始序列的逆序数sum后,我们不难发现,每次将第一个数a放到最后一个位置时,得到的新的序列的逆序数是sum-a+n-a-1,(因为序列中的数都是唯一的,范围0到n-1,所以当第一个数为a时,后面有a个数小于它,将它放到最后面时,前面有n-a-1个数大于它)然后取其中的最小值即可。
代码如下
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.
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
大致题意:给你一个0到n-1这n个数所组成的序列,然后每次将第一个数放到最后一个位置上,得到一个新的序列,总共有n个序列,然你求出这n种情况的最少逆序数。
思路:先考虑如何去求一个序列的逆序数,如果暴力去求的话时间复杂度为n^2,这里我们用线段树来做,每次新加入一个数A[i]时,我们可以在logn的时间内统计此时出A[i]+1到n-1的范围内出现的数的次数,即前i-1个数中有多少个数大于A[i],然后修改A[i]的次数加一。这样总的时间复杂度就降到了nlogn。
然后得到初始序列的逆序数sum后,我们不难发现,每次将第一个数a放到最后一个位置时,得到的新的序列的逆序数是sum-a+n-a-1,(因为序列中的数都是唯一的,范围0到n-1,所以当第一个数为a时,后面有a个数小于它,将它放到最后面时,前面有n-a-1个数大于它)然后取其中的最小值即可。
代码如下
#include<cstring> #include<cstdio> #include<iostream> #include <algorithm> #include<cmath> #define M 5005 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int num[M<<2]; int A[M]; inline void PushPlus(int rt) { num[rt] = num[rt<<1]+num[rt<<1|1]; } void Build(int l, int r, int rt) //建树 { 4000 if(l == r) { num[rt]=0; return ; } int m = ( l + r )>>1; Build(lson); Build(rson); PushPlus(rt); } void Updata(int p,int l, int r, int rt)//单点更新,将num[p]的值变为1,表示p数字出现了 { if( l == r ) { num[rt]=1; return ; } int m = ( l + r ) >> 1; if(p <= m) Updata(p, lson); else Updata(p, rson); PushPlus(rt); } int Query(int L,int R,int l,int r,int rt) { if( L <= l && r <= R ) { return num[rt]; } int m = ( l + r ) >> 1; int ans=0; if(L<=m ) ans+=Query(L,R,lson); if(R>m) ans+=Query(L,R,rson); return ans; } int main() { int n; while(scanf("%d",&n)!=EOF) { Build(0,n-1,1); int sum=0; int ans; for(int i=1;i<=n;i++) { scanf("%d",&A[i]); Updata(A[i],0,n-1,1); sum+=Query(A[i]+1,n-1,0,n-1,1);//统计此时大于A[i]的数在前面出现的次数 } ans=sum; for(int i=1;i<n;i++) { sum=sum+n-A[i]-1-A[i]; ans=min(ans,sum); } printf("%d\n",ans); } return 0; }
相关文章推荐
- 线段树系列-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(单点更新,区间求和)
- 【线段树I:点修改+区间查询】hdu 1394 Minimum Inversion Number
- HDU1394:Minimum Inversion Number(线段树单点更新)
- HDOJ 1394 Minimum Inversion Number 线段树 : 单点更新 成段求和
- HDU 1394 Minimum Inversion Number (线段树:单点增减求和)
- HDU - 1394 Minimum Inversion Number(线段树 单点更新 区间查询)
- hdu1394 Minimum Inversion Number(线段树单点更新||暴力)
- hdu1394 Minimum Inversion Number 最小逆序数 线段树单点更新区间查询
- 数据结构 线段树 hdu1394 Minimum Inversion Number(单点更新)
- Minimum Inversion Number 线段树+单点修改
- HDU1394 Minimum Inversion Number [暴力] [线段树-单点更新]
- HDU 1394 Minimum Inversion Number 线段树 单点更新 求逆序数
- HDU 4893(Wow! Such Sequence!-线段树单点修改+区间求和+改为最近Fib数)
- HDU 1394 Minimum Inversion Number(线段树单点更新)