Minimum Inversion Number BNUOJ 5594
题意:求Inversion后的最小逆序数(n<=5000)
思路:一、暴力。(以n的范围来看貌似可以,未尝试。)
二、树状数组。//就跑的时间来看还是树状数组(46ms)比较快,不过也许是我的线段树(78ms)写疵了。
1.用树状数组求逆序对数。
用样例1 3 6 9 0 8 5 7 4 2说明。sum=0;a[1]=1;sum+=c[n]-c[3]=0;a[3]=1;sum+=c[n]-c[6]=0;a[6]=1;sum+=c[n]-c[9]=0;a[9]=1;sum+=c[n]-c[0]=4;a[0]=1;sum+=c[n]-c[8]=5;a[8]=1;sum+=c[n]-c[5]=8;a[5]=1;sum+=c[n]-c[7]=10;a[7]=1;sum+=c[n]-c[4]=15;a[4]=1;sum+=c[n]-c[2]=22;a[2]=1;
大致思路是这样,在代码里我做了离散化。
2.每次将队首的一个数移至队尾计算逆序数。由于队列中的数为0-n-1。那么,对于队首的x,比它大的有n-x-1个,比它小的有x个。每移动一次,逆序数变化量为(n-x-1)-x.比较更新即可。
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define MAX 5010 5 6 using namespace std; 7 8 struct node{ 9 int pos,val; 10 }a[MAX]; 11 12 int c[MAX]; 13 int x[MAX]; 14 int n; 15 int lowbit(int i){ 16 return(i&(-i)); 17 } 18 int getsum(int i) { 19 int sum =0; 20 while (i>0){ 21 sum += c[i]; 22 i -= lowbit(i); 23 } 24 return sum; 25 } 26 void update(int i, int val){ 27 while (i<=n){ 28 c[i] += val; 29 i += lowbit(i); 30 } 31 } 32 bool cmp(node a,node b){ 33 return a.val>b.val; 34 } 35 36 int main(){ 37 int sum=0; 38 int i; 39 while(scanf("%d",&n)!=EOF){ 40 sum = 0; 41 memset(c,0,sizeof(c)); 42 for(i=1;i<=n;i++){ 43 scanf("%d",&a[i].val); 44 x[i]=a[i].val; 45 a[i].pos = i; 46 } 47 sort(a+1,a+n+1,cmp); 48 for(i=1;i<=n;i++){ 49 sum += getsum(a[i].pos); 50 update(a[i].pos,1); 51 } 52 //printf("%d\n",sum); 53 int ret=sum; 54 for(int i=1;i<=n;++i){ 55 sum+=n-x[i]-x[i]-1; 56 if(sum<ret)ret=sum; 57 } 58 printf("%d\n",ret); 59 } 60 return 0; 61 }
三、线段树。(线段树的作法与树状数组类似。)
更新和维护方法与树状数组一致,只是调用函数和写法的差别。
1 #include <cstdio> 2 3 #define lson l , m , rt << 1 4 #define rson m + 1 , r , rt << 1 | 1 5 const int maxn = 5010; 6 int sum[maxn<<2]; 7 int x[maxn]; 8 void PushUP(int rt) { 9 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 10 } 11 void build(int l,int r,int rt) { 12 if (l == r) { 13 sum[rt]=0; 14 return ; 15 } 16 int m = (l + r) >> 1; 17 build(lson); 18 build(rson); 19 PushUP(rt); 20 } 21 void update(int p,int add,int l,int r,int rt) { 22 if (l == r) { 23 sum[rt] += add; 24 return ; 25 } 26 int m = (l + r) >> 1; 27 if (p <= m) update(p , add , lson); 28 else update(p , add , rson); 29 PushUP(rt); 30 } 31 int query(int L,int R,int l,int r,int rt) { 32 if (L <= l && r <= R) { 33 return sum[rt]; 34 } 35 int m = (l + r) >> 1; 36 int ret = 0; 37 if (L <= m) ret += query(L , R , lson); 38 if (R > m) ret += query(L , R , rson); 39 return ret; 40 } 41 int main() { 42 int n,sum; 43 while(scanf("%d",&n)!=EOF){ 44 build(1,n,1); 45 sum=0; 46 for(int i=1;i<=n;++i){ 47 scanf("%d",&x[i]); 48 sum+=query(x[i]+1,n,1,n,1); 49 update(x[i]+1,1,1,n,1); 50 } 51 int ret=sum; 52 for(int i=1;i<=n;++i){ 53 sum+=n-x[i]-x[i]-1; 54 if(sum<ret)ret=sum; 55 } 56 printf("%d\n",ret); 57 } 58 return 0; 59 }
Q