• 逆序数 POJ 2299 Ultra-QuickSort


    题目传送门

     1 /*
     2     题意:就是要求冒泡排序的交换次数。
     3     逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。
     4     一个排列中逆序的总数就称为这个排列的逆序数。逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。
     5     如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。也是就说,对于n个不同的元素,
     6     先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,
     7     当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。
     8 
     9     接下来有多种做法求解逆序数:1. 暴力;2. 归并排序;3. 线段树-单点更新;4. 树状数组
    10 */
     1 /*
     2     暴力 超时 O(n^2)
     3 */
     4 #include <stdio.h>
     5 
     6 const int MAX_N = 500000;
     7 int a[MAX_N+10];
     8 long long cnt = 0;
     9 
    10 int main(void)        //POJ 2299 Ultra-QuickSort
    11 {
    12     //freopen ("inD.txt", "r", stdin);
    13     int n;
    14     
    15     while (scanf ("%d", &n) != EOF && n)
    16     {
    17         for (int i=1; i<=n; ++i)
    18         {
    19             scanf ("%d", &a[i]);
    20         }
    21 
    22         for (int i=1; i<=n; ++i)
    23         {
    24             for (int j=i+1; j<=n; ++j)
    25             {
    26                 if (a[i] > a[j])
    27                     cnt++;
    28             }
    29         }
    30         printf ("%lld
    ", cnt);
    31         cnt = 0;
    32     }
    33     
    34     return 0;
    35 }
    暴力 超时 O(n^2)
     1 /* 
     2     归并排序是将数列a[p, r]分成两半a[p, q]和a[q+1,r]分别进行归并排序,
     3     然后再将这两半合并起来。在合并的过程中(设p<=i<=q,q+1<=j<=r),
     4     当L[i]<=R[j]时,并不产生逆序数;
     5     当L[i]>R[j]时,在前半部分中比L[i]大的数都比R[j]大,
     6     将R[j]放在L[i]前面的话,逆序数要加上q+1-i。
     7     因此,可以在归并排序中的合并过程中计算逆序数。 
     8  
     9     这道题充分印证了,即使merge本身可能用的不多,但分冶的思想却是无所不在:)
    10 */
    11 #include <stdio.h>
    12 
    13 const int MAX_N = 500000;
    14 const int INF = 0xffffff;
    15 int a[MAX_N+10];
    16 long long cnt = 0;
    17  
    18 void Merge(int *a, int p, int q, int r)
    19 {
    20     int n1 = q - p + 1;
    21     int n2 = r - q;
    22     int L[MAX_N/2+1], R[MAX_N/2+1];
    23     int i, j;
    24     for (i=1; i<=n1; ++i)    L[i] = a[p+i-1];
    25     for (j=1; j<=n2; ++j)    R[j] = a[q+j];
    26     L[n1+1] = INF;    R[n2+1] = INF;
    27 
    28     i = 1;    j = 1;
    29     for (int k=p; k<=r; ++k)
    30     {
    31         if (L[i] <= R[j])
    32         {
    33             a[k] = L[i++];
    34         }
    35         else
    36         {
    37             a[k] = R[j++];
    38             cnt += n1 - i + 1;         //此步骤是在归并排序法中加的一句,用来计数求逆序数的数目
    39         }
    40     }
    41 }
    42 
    43 void MergeSort(int *a, int p, int r)
    44 {
    45     int q;
    46     if (p < r)
    47     {
    48         q = (p + r) / 2;
    49         MergeSort (a, p, q);
    50         MergeSort (a, q+1, r);
    51         Merge (a, p, q, r);
    52     }
    53 }
    54 
    55 int main(void)        //POJ 2299 Ultra-QuickSort
    56 {
    57     //freopen ("inD.txt", "r", stdin);
    58     int n;
    59     
    60     while (scanf ("%d", &n) != EOF && n)
    61     {
    62         for (int i=1; i<=n; ++i)
    63         {
    64             scanf ("%d", &a[i]);
    65         }
    66         MergeSort (a, 1, n);
    67         printf ("%lld
    ", cnt);
    68         cnt = 0;
    69     }
    70     
    71     return 0;
    72 }
    归并排序
     1 /*
     2     线段树-单点更新
     3 */
     4 #include <cstdio>
     5 #include <algorithm>
     6 #define lson l, m, rt << 1
     7 #define rson m+1, r, rt << 1 | 1
     8 using namespace std;
     9 
    10 const int MAX_N = 500000;
    11 const int INF = 0x3f3f3f3f;
    12 int a[MAX_N];
    13 int b[MAX_N];
    14 int sum[MAX_N << 2];
    15 
    16 void pushup(int rt)
    17 {
    18     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    19 }
    20 
    21 void build(int l, int r, int rt)
    22 {
    23     sum[rt] = 0;
    24     if (l == r) return ;
    25     int m = (l + r) >> 1;
    26     build (lson);
    27     build (rson);
    28 
    29     pushup (rt);
    30 }
    31 
    32 void update(int p, int l, int r, int rt)
    33 {
    34     if (l == r)
    35     {
    36         sum[rt]++;      //记录次数
    37         return ;
    38     }
    39     int m = (l + r) >> 1;
    40     if (p <= m)
    41     {
    42         update (p, lson);
    43     }
    44     else
    45         update(p, rson);
    46     pushup (rt);
    47 }
    48 
    49 int query(int ql, int qr, int l, int r, int rt)
    50 {
    51     if (ql <= l && r <= qr)
    52     {
    53         return sum[rt];
    54     }
    55     int m = (l + r) >> 1;
    56     int ans = 0;
    57     if (ql <= m)    ans += query (ql, qr, lson);
    58     if (qr > m)     ans += query (ql, qr, rson);
    59 
    60     return ans;
    61 }
    62 
    63 int BinarySearch(int key, int l, int r)
    64 {
    65     while (r >= l)
    66     {
    67         int mid = (l + r) >> 1;
    68         if (key == b[mid])    return mid;
    69         if (key < b[mid])    r = mid - 1;
    70         else    l = mid + 1;
    71     }
    72 }
    73 
    74 int main(void)
    75 {
    76     //freopen ("inD.txt", "r", stdin);
    77     int n;
    78     while (~scanf ("%d", &n) && n)
    79     {
    80         build (0, n-1, 1);
    81         
    82         for (int i=1; i<=n; ++i)   
    83         {
    84             scanf ("%d", &a[i]);
    85             b[i] = a[i];
    86         }
    87         sort (b+1, b+n+1);
    88         long long ans = 0;
    89         for (int i=1; i<=n; ++i)
    90         {
    91             int x = BinarySearch (a[i], 1, n);
    92             ans += query (x, n, 1, n, 1);
    93             update (x, 1, n, 1);
    94         }
    95         printf ("%lld
    ", ans);
    96     }
    97 
    98     return 0;
    99 }
    线段树-单点更新
    编译人生,运行世界!
  • 相关阅读:
    诸侯安置
    可可西里
    直线交点
    切割多边形
    ACM挑战程序设计竞赛1.1抽签
    朝鲜战争:轰炸大小和岛
    星际争霸II 战斗问题
    乒乓球
    瑞士轮
    NOIP 2010 普及组解题报告
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4392008.html
Copyright © 2020-2023  润新知