hdu1394 Minimum Inversion Number 线段树和树状数组

  题意:

  输入一个长度 n

  第二行给出长度为n的数组,数组的值刚好为0到n-1这n个数。

     然后每次把数组的第一个数放到最后一个,放n-1次,共有n个排列,这n个排列就有n个逆序数,输出这n个逆序数的最小值。

我的做法:

1、每次输入a[i]后,都把a[i] ++;

2、求出第一个排列的逆序数

3、递推求出所有的逆序数

那怎么求1呢?

对于每一个a[i],求出1到i-1 中比它大的个数,然后相加,即可得。若用朴素的查找,肯定会超时的,所以这里就利用线段树或者树状数组来快速查找。

线段树版本:

 

技术分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #define lson l,m,rt<<1
 4 #define rson m+1,r,rt<<1|1
 5 const int maxn=5010;
 6 int c[maxn<<2];
 7 int a[maxn];
 8 int sum[maxn];
 9 void pushup(int rt)
10 {
11     c[rt]=c[rt<<1]+c[rt<<1|1];
12 }
13 void update(int p,int add,int l,int r,int rt)
14 {
15     if(l==r){
16         c[rt]+=add;
17         return;
18     }
19     int m=(l+r)>>1;
20     if(p<=m)
21         update(p,add,lson);
22     else
23         update(p,add,rson);
24     pushup(rt);
25 }
26 int query(int L,int R,int l,int r,int rt)
27 {
28     if(L<=l&&R>=r)
29         return c[rt];
30     int m=(l+r)>>1;
31     int ret=0;
32     if(L<=m)
33         ret+=query(L,R,lson);
34     if(R>m)
35         ret+=query(L,R,rson);
36     return ret;
37 }
38 int main()
39 {
40     int n;
41     while(scanf("%d",&n)!=EOF){
42         sum[1]=0;
43         memset(c,0,sizeof(c));
44         for(int i=1;i<=n;i++){
45             scanf("%d",&a[i]);
46             a[i]++;
47             sum[1]+=query(a[i],n,1,n,1);
48             update(a[i],1,1,n,1);
49         }
50         for(int i=2;i<=n;i++)
51             sum[i]=sum[i-1]+n+1-2*a[i-1];
52         int ans=n*n;
53         for(int i=1;i<=n;i++)
54             if(sum[i]<ans)
55                 ans=sum[i];
56         printf("%d\n",ans);
57     }
58     return 0;
59 }
View Code

 

用了46ms

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。