1. 程式人生 > >hdu1394(枚舉/樹狀數組/線段樹單點更新&區間求和)

hdu1394(枚舉/樹狀數組/線段樹單點更新&區間求和)

splay nbsp one 包括 一個 hid closed 當前 初始

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1394

題意:給出一個循環數組,求其逆序對最少為多少;

思路:對於逆序對: 交換兩個相鄰數,逆序數 +1 或 -1, 交換兩個不相鄰數 a, b, 逆序數 += 兩者間大於 a 的個數 - 兩者間小於 a 的個數;

所以只要求出初始時的逆序對數,就可以推出其余情況時的逆序對數.對於求初始逆序對數,這裏 n 只有 5e3,可以直接暴力 / 樹狀數組 / 線段樹 / 歸並排序;

代碼:

1.直接暴力

技術分享
 1 #include <iostream>
 2 #include <stdio.h>
 3
using namespace std; 4 5 const int MAXN = 5e3 + 10; 6 int a[MAXN]; 7 8 int main(void){ 9 int n, ans = 0; 10 while(~scanf("%d", &n)){ 11 ans = 0; 12 for(int i = 0; i < n; i++){ 13 scanf("%d", &a[i]); 14 for(int j = 0; j < i; j++){ 15 if
(a[j] > a[i]) ans++; 16 } 17 } 18 int cnt = ans; 19 for(int i = 0; i < n; i++){ 20 cnt += (n - a[i] - 1) - a[i]; 21 ans = min(ans, cnt); 22 } 23 printf("%d\n", ans); 24 } 25 return 0; 26 }
View Code

2.樹狀數組

技術分享
 1
#include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 6 const int MAXN = 5e3 + 10; 7 int tree[MAXN], a[MAXN], n; 8 9 int lowbit(int x){ 10 return x & (-x); 11 } 12 13 void updata(int x, int d){ 14 while(x <= n){ 15 tree[x] += d; 16 x += lowbit(x); 17 } 18 } 19 20 int sum(int x){ 21 int ans = 0; 22 while(x > 0){ 23 ans += tree[x]; 24 x -= lowbit(x); 25 } 26 return ans; 27 } 28 29 int main(void){ 30 int ans = 0; 31 while(~scanf("%d", &n)){ 32 ans = 0; 33 memset(tree, 0, sizeof(tree)); 34 for(int i = 1; i <= n; i++){ 35 scanf("%d", &a[i]); 36 updata(a[i] + 1, 1); 37 ans += i - sum(a[i] + 1);//當前是第 i 個數,減去a[i]前面(這裏包括了a[i])的數就是a[i]後面的數了,即可以和a[i]組成逆序對的數的數目 38 // ans += sum(n) - sum(a[i] + 1); 39 } 40 int cnt = ans; 41 for(int i = 1; i <= n; i++){ 42 cnt += (n - a[i] - 1) - a[i]; 43 ans = min(ans, cnt); 44 } 45 printf("%d\n", ans); 46 } 47 return 0; 48 }
View Code

3.線段樹

技術分享
 1 #include <iostream>
 2 #include <stdio.h>
 3 #define lson l, mid, rt << 1
 4 #define rson mid + 1, r, rt << 1 | 1
 5 using namespace std;
 6 
 7 const int MAXN = 5e3 + 10;
 8 int sum[MAXN << 2], a[MAXN];
 9 
10 void push_up(int rt){
11     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
12 }
13 
14 void build(int l, int r, int rt){
15     sum[rt] = 0;
16     if(l == r) return;
17     int mid = (l + r) >> 1;
18     build(lson);
19     build(rson);
20 }
21 
22 void update(int p, int x, int l, int r, int rt){
23     if(l == r){
24         sum[rt] += x;
25         return;
26     }
27     int mid = (l + r) >> 1;
28     if(p <= mid) update(p, x, lson);
29     else update(p, x, rson);
30     push_up(rt);
31 }
32 
33 int query(int L, int R, int l, int r, int rt){
34     if(l >= L && r <= R) return sum[rt];
35     int mid = (l + r) >> 1;
36     int ans = 0;
37     if(L <= mid) ans += query(L, R, lson);
38     if(R > mid) ans += query(L, R, rson);
39     return ans;
40 }
41 
42 int main(void){
43     int n, ans = 0;
44     while(~scanf("%d", &n)){
45         ans = 0;
46         build(0, n-1, 1);
47         for(int i = 0; i < n; i++){
48             scanf("%d", &a[i]);
49             ans += query(a[i], n - 1, 0, n - 1, 1);
50             update(a[i], 1, 0, n - 1, 1);
51         }
52         int cnt = ans;
53         for(int i = 0; i < n; i++){
54             cnt += (n - a[i] - 1) - a[i];
55             ans = min(ans, cnt);
56         }
57         printf("%d\n", ans);
58     }
59     return 0;
60 }
View Code

hdu1394(枚舉/樹狀數組/線段樹單點更新&區間求和)