• hihocoder1524


    题目链接

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    给定一个1-N的排列A1, A2, ... AN,如果Ai和Aj满足i < j且Ai > Aj,我们就称(Ai, Aj)是一个逆序对。  

    求A1, A2 ... AN中所有逆序对的数目。  

    输入

    第一行包含一个整数N。  

    第二行包含N个两两不同整数A1, A2, ... AN。(1 <= Ai <= N)  

    对于60%的数据 1 <= N <= 1000  

    对于100%的数据 1 <= N <= 100000

    输出

    一个整数代表答案

    样例输入
    5
    3 2 4 5 1
    样例输出
    5
     求逆序对,两种方法,一个是用树形数组做,一个是用归并排序做。两种都试了一遍,有一个地方比较坑就是数组类型必须是long long。不然会WA,题目却没有明显信息说要long long。。这个地方可以说是很坏坏了。
     
    树形数组ac代码:
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<vector>
     6 #include<iomanip>
     7 using namespace std;
     8 
     9 
    10 //1524 : 逆序对
    11 const int maxn = 1e5 + 5;
    12 int n;
    13 long long a[maxn], b[maxn];
    14 int lowbit(int i)
    15 {
    16     return i&-i;
    17 }
    18 void update(int i)
    19 {
    20     while (i <= n)
    21     {
    22         b[i]++;
    23         i += lowbit(i);
    24     }
    25 }
    26 long long sum(int i)
    27 {
    28     long long cnt = 0;
    29     while (i)
    30     {
    31         cnt += b[i];
    32         i -= lowbit(i);
    33     }
    34     return cnt;
    35 }
    36 int main()
    37 {
    38     cin >> n;
    39     for (int i = 1;i <= n;i++)
    40     {
    41         cin >> a[i];
    42     }
    43     memset(b, 0, sizeof(b));
    44     long long res = 0;
    45     for (int i = n;i >= 1;i--)
    46     {
    47         update(a[i]);
    48         res += sum(a[i] - 1);
    49     }
    50     cout << res << endl;
    51     return 0;
    52 }

    树形数组这个东西还是比较有趣的。这个算法可以说是比较天才了。

    具体的树形数组详解可以看这个博主的http://blog.csdn.net/ljd4305/article/details/10101535

    归并排序的ac代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<vector>
     6 #include<iomanip>
     7 using namespace std;
     8 
     9 
    10 //1524 : 逆序对
    11 const int maxn = 1e5 + 5;
    12 int n;
    13 long long a[maxn],b[maxn];
    14 long long cnt;
    15 
    16 void merge_sort(long long * a, int l, int r)
    17 {
    18     int mid = (l + r) >> 1;
    19     int m = l, n = mid + 1;
    20     int pos = l;
    21     while (m<=mid&&n<=r)
    22     {
    23         if (a[m] < a[n])
    24         {
    25             b[pos++] = a[m++];
    26         }
    27         else
    28         {
    29             b[pos++] = a[n++];
    30             cnt+=mid-m+1;
    31         }
    32     }
    33 
    34     while (m <= mid) b[pos++] = a[m++];
    35     while (n <= r) b[pos++] = a[n++];
    36     for (int i = l;i <= r;i++)
    37         a[i] = b[i];
    38 }
    39 void merge(long long * a, int l, int r)
    40 {
    41     if (l >= r) return;
    42     int mid = (l + r) >>1;
    43     merge(a, l, mid);
    44     merge(a, mid+1, r);
    45     merge_sort(a, l, r);
    46 }
    47 
    48 int main()
    49 {
    50     cnt = 0;
    51     cin >> n;
    52     for (int i = 1;i <= n;i++)
    53     {
    54         cin >> a[i];
    55     }
    56     merge(a, 1, n);
    57     cout << cnt << endl;
    58     return 0;
    59 }

    归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并排序中的合并过程中计算逆序数。

    可以参考http://blog.csdn.net/acdreamers/article/details/16849761

  • 相关阅读:
    修改input:file样式
    gruntjs
    C#Lambda表达式
    C#委托与事件讲解(一)
    Linq的语法以及常用的扩展方法
    正则表达式就这么简单!
    C#参考之sealed密封类(转)
    Python学习(六)
    Python学习(一)
    自动化测试之JDBC连接、分布式负载
  • 原文地址:https://www.cnblogs.com/weedboy/p/7074399.html
Copyright © 2020-2023  润新知