@Chilling
        
        2017-02-16T09:58:19.000000Z
        字数 2128
        阅读 1165
    线段树
Problem Description
The inversion number of a given number sequence is the number of pairs that satisfy i < j and .
For a given sequence of numbers , 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:
(where m = 0 - the initial seqence) 
 (where m = 1) 
 (where m = 2) 
... 
 (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
题意:输入n个数,然后按照题目要求交换这n个数的位置,求最小的逆序数是多少。
交换的法则,m从0到n-1变化,每次将第一个数拿到最后,如下:
...
求在这n个序列中逆序数最小是多少。
分析:先用线段树求出最初的逆序数,(也可以归并求出),再循环n-1次,逆序数有这么一个规律:
原来的逆序数是ans,把a[0]移到最后之后,减少逆序数a[0],同时增加逆序数n-a[0]-1个,总的变化ans-a[0]+n-a[0]-1。
因此每次的逆序数ans=ans-a[i]+n-a[i]-1,求出最小的即可。
#include<stdio.h>#include<algorithm>#define maxn 5005using namespace std;int a[maxn];struct node{int l,r,sum;}s[4*maxn];void build(int id,int l,int r){s[id].l=l;s[id].r=r;if(l==r)s[id].sum=0;else{int mid=(l+r)/2;build(id*2,l,mid);build(id*2+1,mid+1,r);s[id].sum=0;}}void rep(int id,int x,int y)//y=1{if(s[id].l==s[id].r)s[id].sum=y;else{int mid=(s[id].l+s[id].r)/2;if(x<=mid)rep(id*2,x,y);elserep(id*2+1,x,y);s[id].sum=s[id*2].sum+s[id*2+1].sum;}}int sum(int id,int l,int r){if(l<=s[id].l&&s[id].r<=r)return s[id].sum;else{int mid=(s[id].l+s[id].r)/2;if(r<=mid)return sum(id*2,l,r);else if(l>mid)return sum(id*2+1,l,r);elsereturn sum(id*2,l,r)+sum(id*2+1,l,r);}}int main(){int n,ss,ans;while(scanf("%d",&n)!=EOF){ss=0;build(1,0,n-1);for(int i=0;i<n;i++){scanf("%d",&a[i]);ss+=sum(1,a[i],n-1);rep(1,a[i],1);}ans=ss;//初始的逆序数// printf("%d\n",ans);for(int i=0;i<n;i++){ans=min(ans,ss-a[i]+n-a[i]-1);ss=ss-a[i]+n-a[i]-1;}printf("%d\n",ans);}return 0;}