HDU1394(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 }
屌丝终有逆袭日,*******。