hdu 1394 Minimum Inversion Number

题目链接:hdu 1394 Minimum Inversion Number

该题是求最小逆序对的扩展。可以使用树状数组来实现。对于$n$个数的序列$A$,其第$i$个数($i\in [0,n)$)的逆序数$r_i$可以表示为它的角标$i$减去在它之前且不大于它的数的个数。例如对序列A = {1,3,5,9,0,8,5,7,4,2}中的数,A[8] = 4。其逆序数$r_8 = 8 - 3 = 5$,第二个3表示三个在它前面且比它小的数:{1,3,0}。从而我们可以得到第$i$个数的逆序数公式:

\begin{equation} r_i = i - \sum_{0 \leq j < i And A_j \leq A_i } 1 \end{equation}

对于整个序列$A$有

\begin{equation} R = \sum_{0 \leq i < n}r_i \end{equation}

可以使用树状数组的前i项的和sum(i)函数来快速的计算$\sum_{0 \leq j < i And A_j \leq A_i } 1$,并且使用add(i+1)来对该数进行计数。

得到初始数列的逆序数后,可以轻松地计算变换后序列的逆序数。

如果删除掉第一个数$A_1$,那么逆序数会减小$A_1$。

在把第一个数放到数列结尾,那么逆序数又会增加$n-A_1-1$

从而可以尝试所有的变换方法,最终取最小值即可。

代码如下:

 1 #include <cstdlib>

 2 #include <cstdio>

 3 #include <iostream>

 4 #include <cstring>

 5 #define MAXN  5005

 6 using namespace std;

 7 int bit[MAXN];

 8 int arr[MAXN];

 9 int n;

10 int lowbit(int x)

11 {

12     return x&(-x);

13 }

14 int sum(int x)

15 {

16     int ans = 0;

17     while( x > 0 )

18     {

19         ans += bit[x];

20         x -= lowbit(x);

21     }

22     return ans;

23 }

24 void add(int l, int x)

25 {

26     while( l <= n )

27     {

28         bit[l] += x;

29         l += lowbit(l);

30     }

31 }

32 int main(int argc, char *argv[])

33 {

34     while( scanf("%d", &n) != EOF )

35     {

36         int ans = 0;

37         memset(bit, 0, sizeof(bit));

38         for( int i = 0 ; i < n ; i++ )

39         {

40             scanf("%d", &arr[i]);

41             ans += i - sum(arr[i]+1);

42             add(arr[i]+1, 1);

43         }

44         int mi = ans;

45         for( int i = 0 ; i < n ; i++ )

46         {

47             ans = ans - arr[i] + n - arr[i] -1;

48             mi = ans > mi ? mi : ans;

49         }

50         printf("%d\n", mi);

51     }

52 }

 

你可能感兴趣的:(version)