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.
InputThe 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.
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.
OutputFor each case, output the minimum inversion number on a single line.
Sample Input
10 1 3 6 9 0 8 5 7 4 2Sample Output
16
题意:给一个0-n-1的排列,这个排列中的逆序数为数对 (ai, aj) 满足 i < j and ai > aj的个数。依次把第一个数放到排列的末尾会得到另外n-1个排列,求这n个排列中的最小的逆序数。
思路:首先要求第一个排列的逆序数。假如第一个逆序数为s0,当把a0从首位移到末位时,新得到的s1应该是在s0的基础上加上比a0大的数的个数,减去比a0小的数的个数。由于这一串数是一个0~n-1的排列,所以比a0大的数的个数为 (n - 1) - (a0 + 1) + 1 = n - a0 - 1,比a0小的数的个数为 (a0-1)-0+1=a0,所以s1 = s0 + n - a0 - a0 - 1.逆序数就是求对于每个数aj,在坐标比aj小的前提下,求比它大的数的个数。建树的时候把每个节点都初始化为0,每当插入一个数,就在这个数对应的叶子节点上加1,同时更新包含这个点的线段所对应的非叶子节点(加1),一层层更新上去,区间求和即可。
#include <cstdio> #include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 #define mid (l+r)>>1 #define abbreviations int l,int r,int rt const int maxn = 5005; int sum[maxn<<2]; int a[maxn]; void PushUP(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(abbreviations) { sum[rt] = 0; if(l == r) return; int m = mid; build(lson); build(rson); } int query(int L,int R, abbreviations) { if(L <= l && r <= R) return sum[rt]; int m = mid; int ret = 0; if(L <= m) ret += query(L,R,lson); if(R>m) ret += query(L,R,rson); return ret; } void update(int p, abbreviations) { if(l == r) { sum[rt]++; return; } int m = mid; if(p <= m) update(p,lson); else update(p,rson); PushUP(rt); } int main() { int n; while(~scanf("%d",&n)) { build(0, n-1, 1); int sum = 0; for(int i = 0; i < n; i++) { scanf("%d", &a[i]); sum += query(a[i], n-1, 0, n-1, 1); update(a[i], 0, n-1, 1); } int minm = sum; for(int i = 0; i < n; i++) { sum += n - a[i] - a[i] - 1; minm = min(minm, sum); } printf("%d\n", minm); } return 0; }