地址:http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意:给n个数字(0到n-1无重复),可以拿前面任意m个放到末尾。求拿多少个数字放到末尾后数列的逆序数最小。

mark:非常经典的一个题目,来自zoj月赛。先用线段树/点树/树状数组/合并排序求出原数列的逆序数,然后递推出所有情况的逆序数取最小。

这题真的是非常经典,所以4种方法我都写了一次。

代码:

线段树(62ms、284k、991B):

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

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-02-18
猜你喜欢
  • 2021-11-27
  • 2022-12-23
  • 2021-05-21
  • 2021-07-04
  • 2021-05-27
  • 2022-03-05
相关资源
相似解决方案