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