1 /* 2 求逆序数的四种方法 3 */
1 /* 2 1. O(n^2) 暴力+递推 法:如果求出第一种情况的逆序列,其他的可以通过递推来搞出来,一开始是t[1],t[2],t[3]....t[N] 3 它的逆序列个数是N个,如果把t[1]放到t[N]后面,逆序列个数会减少t[1]个,相应会增加N-(t[1]+1)个 4 */ 5 #include <cstdio> 6 #include <cstring> 7 #include <algorithm> 8 using namespace std; 9 10 const int MAX_N = 10000 + 10; 11 const int INF = 0x3f3f3f3f; 12 int a[MAX_N]; 13 int num[MAX_N]; 14 15 int main(void) //HDOJ 1394 Minimum Inversion Number 16 { 17 //freopen ("inC.txt", "r", stdin); 18 int n; 19 20 while (~scanf ("%d", &n)) 21 { 22 memset (num, 0, sizeof (num)); 23 for (int i=1; i<=n; ++i) 24 { 25 scanf ("%d", &a[i]); 26 //a[n+i] = a[i]; 27 } 28 int t = 0; int sum = 0; 29 for (int i=1; i<=n; ++i) //先求解最初的数列逆序数 30 { 31 for (int j=i+1; j<=n; ++j) 32 { 33 if (a[i] > a[j]) 34 { 35 sum++; 36 } 37 } 38 } 39 //printf ("%d\n", sum); 40 int ans = INF; 41 for (int i=1; i<=n; ++i) //更新sum,找最小 42 { 43 sum = sum - a[i] + (n - a[i] - 1); //the next line contains a permutation of the n integers from 0 to n-1. 44 //printf ("%d\n", res); //从0到n-1的整数 所以这里用a[i] 读题不仔细 。。。。 45 ans = min (sum, ans); 46 } 47 printf ("%d\n", ans); 48 } 49 50 return 0; 51 }
O(n^2) 暴力+递推
nlogn归并算法
1 /* 2 3. nlogn 线段树-单点更新:更新比a[i]大的个数 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #define lson l, m, rt << 1 7 #define rson m+1, r, rt << 1 | 1 8 9 const int MAX_N = 5000 + 10; 10 const int INF = 0x3f3f3f3f; 11 int a[MAX_N]; 12 int sum[MAX_N << 2]; 13 14 void pushup(int rt) 15 { 16 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 17 } 18 19 void build(int l, int r, int rt) 20 { 21 sum[rt] = 0; 22 if (l == r) return ; 23 int m = (l + r) >> 1; 24 build (lson); 25 build (rson); 26 } 27 28 void update(int p, int l, int r, int rt) 29 { 30 if (l == r) 31 { 32 sum[rt]++; //记录次数 33 return ; 34 } 35 int m = (l + r) >> 1; 36 if (p <= m) 37 { 38 update (p, lson); 39 } 40 else 41 update(p, rson); 42 pushup (rt); 43 } 44 45 int query(int ql, int qr, int l, int r, int rt) 46 { 47 if (ql <= l && r <= qr) 48 { 49 return sum[rt]; 50 } 51 int m = (l + r) >> 1; 52 int ans = 0; 53 if (ql <= m) ans += query (ql, qr, lson); 54 if (qr > m) ans += query (ql, qr, rson); 55 56 return ans; 57 } 58 59 int main(void) //HDOJ 1394 Minimum Inversion Number 60 { 61 //freopen ("inC.txt", "r", stdin); 62 int n; 63 while (~scanf ("%d", &n)) 64 { 65 //memset (num, 0, sizeof (num)); 66 build (0, n-1, 1); 67 int sum = 0; 68 for (int i=1; i<=n; ++i) 69 { 70 scanf ("%d", &a[i]); 71 sum += query (a[i], n-1, 0, n-1, 1); 72 update (a[i], 0, n-1, 1); 73 } 74 int ans = sum; 75 for (int i=1; i<=n; ++i) 76 { 77 sum = sum - a[i] + (n - a[i] - 1); 78 ans = std::min (sum, ans); 79 } 80 printf ("%d\n", ans); 81 } 82 83 return 0; 84 }
nlogn 线段树-单点更新
1 /* 2 4. 树状数组 3 */ 4 #include <stdio.h> 5 #include <string.h> 6 #include <algorithm> 7 using namespace std; 8 const int MAXN=5050; 9 int c[MAXN]; 10 int a[MAXN]; 11 int n; 12 13 int lowbit(int x) 14 { 15 return x&(-x); 16 } 17 18 void add(int i,int val) 19 { 20 while(i<=n) 21 { 22 c[i]+=val; 23 i+=lowbit(i); 24 } 25 } 26 27 int sum(int i) 28 { 29 int s=0; 30 while(i>0) 31 { 32 s+=c[i]; 33 i-=lowbit(i); 34 } 35 return s; 36 } 37 38 int main() //HDOJ 1394 Minimum Inversion Number 39 { 40 //freopen ("inC.txt", "r", stdin); 41 while(scanf("%d",&n)!=EOF) 42 { 43 int ans=0; 44 memset(c,0,sizeof(c)); 45 for(int i=1;i<=n;i++) 46 { 47 scanf("%d",&a[i]); 48 a[i]++; 49 ans+=sum(n)-sum(a[i]); 50 add(a[i],1); 51 } 52 int Min=ans; 53 for(int i=1;i<=n;i++) 54 { 55 ans+=n-a[i]-(a[i]-1); 56 if(ans<Min)Min=ans; 57 } 58 printf("%d\n",Min); 59 } 60 61 return 0; 62 }
树状数组
时间: 2024-10-12 03:24:17