HDU1394(Minimum Inversion Number)

题目地址:Minimum Inversion Number

 

题目大意:

    求逆序对数,求循环移位后逆序数的最小值,意思一次将第一位移到最后一位,然后计算逆序对数,求出最小的那个。

 

解题思路:

     因为是序列0->n-1区间的数,所以当你求的,它给出的a1.a2...an-1的逆序对数时cnt,推出如果移位后:设移位a[0],则移位后的逆序对数为 cnt-a[0]+(n-a[i]-1)。知道公式所以先求出给出序列的逆序对,然后从0->n-1移位求出最小的min数即可。

可以用:线段数、树状数组代码、和归并做。

线段数:开0->n-1的线段数,然后一次将给出a[i]添加到线段数中,然后计算a[i+1]时就可以对线段数中a[i+1]->n-1区间查找,计算在该区间已经有多少个数已经被添加完成,说明这个数出现在a[i+1]的前面(因为这个区间都大于a[i+1])。

 

代码:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cstdio>
  7 #include <string>
  8 #include <bitset>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <cmath>
 13 #include <list>
 14 //#include <map>
 15 #include <set>
 16 using namespace std;
 17 /***************************************/
 18 #define ll long long
 19 #define int64 __int64
 20 #define PI 3.1415927
 21 /***************************************/
 22 const int INF = 0x7f7f7f7f;
 23 const double eps = 1e-8;
 24 const double PIE=acos(-1.0);
 25 const int d1x[]= {0,-1,0,1};
 26 const int d1y[]= {-1,0,1,0};
 27 const int d2x[]= {0,-1,0,1};
 28 const int d2y[]= {1,0,-1,0};
 29 const int fx[]= {-1,-1,-1,0,0,1,1,1};
 30 const int fy[]= {-1,0,1,-1,1,-1,0,1};
 31 const int dirx[]= {-1,1,-2,2,-2,2,-1,1};
 32 const int diry[]= {-2,-2,-1,-1,1,1,2,2};
 33 /*vector <int>map[N];map[a].push_back(b);int len=map[v].size();*/
 34 /***************************************/
 35 void openfile()
 36 {
 37     freopen("data.in","rb",stdin);
 38     freopen("data.out","wb",stdout);
 39 }
 40 priority_queue<int> qi1;
 41 priority_queue<int, vector<int>, greater<int> >qi2;
 42 /**********************华丽丽的分割线,以上为模板部分*****************/
 43 const int M=5010;
 44 struct tree
 45 {
 46     int sum;
 47     int left,right;  //记录区间的左右闭区间坐标
 48 } node[M*4];  //需开四倍的空间大小
 49 int p[M];
 50 int cnt;
 51 void build__tree(int id,int l,int r)  //建树
 52 {
 53     int mid=(l+r)/2;
 54     node[id].left=l;   //初始化赋值区间的坐标
 55     node[id].right=r;
 56     if (l==r)
 57     {
 58         node[id].sum=0;  //初始化区间节点的val值
 59         return ;
 60     }
 61     build__tree(id*2,l,mid);  //左孩子
 62     build__tree(id*2+1,mid+1,r); //右孩子
 63     node[id].sum=node[id*2].sum+node[id*2+1].sum;  //通过递归将各个区间节点val更新
 64 }
 65 int sum(int id,int l,int r)  //区间的更新
 66 {
 67     int mid=(node[id].left+node[id].right)/2;
 68     if (node[id].left==l&&node[id].right==r)
 69         return node[id].sum;
 70     if (l>mid)   //[l,r]在右孩子部分
 71         return sum(id*2+1,l,r);
 72     else if (r<=mid) // [l,r]在左孩子部分
 73         return sum(id*2,l,r);
 74     else  //[l,r]区间,左右孩子都有分别递归。
 75         return sum(id*2,l,mid)+sum(id*2+1,mid+1,r);
 76 }
 77 void updata(int id,int pos,int val)
 78 {
 79     int mid=(node[id].left+node[id].right)/2;
 80     if (node[id].left==pos&&node[id].right==pos)
 81     {
 82         node[id].sum+=val;
 83         return ;
 84     }
 85     if (pos<=mid)
 86         updata(id*2,pos,val);
 87     else
 88         updata(id*2+1,pos,val);
 89     node[id].sum=node[id*2].sum+node[id*2+1].sum;
 90 }
 91 int a[5010];
 92 int main()
 93 {
 94     int n;
 95     while(scanf("%d",&n)!=EOF)
 96     {
 97         int i,j;
 98         int cnt=0;
 99         build__tree(1,0,n-1);
100         for(i=0; i<n; i++)
101             scanf("%d",&a[i]);
102         for(i=0; i<n; i++)
103         {
104             cnt+=sum(1,a[i],n-1);
105             updata(1,a[i],1);
106         }
107         int min=cnt;
108         for(i=0;i<n;i++)
109         {
110             cnt-=a[i];
111             cnt+=n-a[i]-1;
112             if (cnt<min)
113                 min=cnt;
114         }
115         printf("%d\n",min);
116     }
117     return 0;
118 }
View Code

 

posted @ 2014-10-07 16:40  kinghold  Views(206)  Comments(0Edit  收藏  举报