题目链接:https://vjudge.net/problem/POJ-2299

推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/7429868

题目意思就是让我们把无序的一些数字经过相邻数字间两两交换,最后变成不递减的数字。我们要求出最少要交换的次数。

逆序对(百度的):对于一个包含N个非负整数的数组,A[1..n],A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。

了解了一下树状数组就过来做这题了,一开始用map容器,一直TLE,后面看了论坛,发现不用map容器编号就可以过,并且还可以用归并排序来写,这两种方法都可以用来求逆序对数量。

树状数组:

因为数字最大可以达到999999999,我们用数组是存不下来的,所以我们要给每一个数字编号,

假设现在就是        9 1 0 5 4

那么我给它们编一个号码就是    1 2 3 4 5    状态一

我们要把它们用两两交换的方法来进行排序,排序之后就是  0 1 4 5 9

对应的编号就是                     3 2 5 4 1  状态二

那现在问题就可以看成我们把编号1到5从状态一用相邻数字交换点的方法变换到状态二,它等同于从状态二变换到状态一,我们现在就讨论从状态二变换到状态一需要的步数就可以了,那么我们看状态二,从左到右枚举每一个数字,每次加上它前面比他大的数字的数量(就相当于把他交换到所有比他大的数字前面),这个用树状数组里面求区间和的操作就可以了,假设现在编号是k,那么加的数量就是函数sum(n)-sum(k)。恩,没了。

代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<map>
  6. #include<stack>
  7. #include<cmath>
  8. #include<vector>
  9. #include<set>
  10. #include<cstdio>
  11. #include<string>
  12. #include<deque>
  13. using namespace std;
  14. typedef long long LL;
  15. #define eps 1e-8
  16. #define INF 0x3f3f3f3f
  17. #define maxn 500005
  18. struct node{
  19. int index,value;//编号和一开始的值
  20. }a[maxn];
  21. LL b[maxn],ans;//要用long long
  22. int n;
  23. bool cmp(node s1,node s2){
  24. return s1.value<s2.value;
  25. }
  26. int lowbit(int x){
  27. return x&(-x);
  28. }
  29. LL sum(int x){
  30. LL ans=;
  31. while(x>){
  32. ans+=b[x];
  33. x-=lowbit(x);
  34. }
  35. return ans;
  36. }
  37. void add(int x){
  38. while(x<maxn){
  39. b[x]++;
  40. x+=lowbit(x);
  41. }
  42. }
  43. int main()
  44. {
  45. while(scanf("%d",&n)&&n){
  46. ans=;
  47. memset(b,,sizeof(b));
  48. for(int i=;i<=n;i++){//编号我们从1开始,防止后面单点修改的时候死循环
  49. scanf("%d",&a[i].value);
  50. a[i].index=i;
  51. }
  52. sort(a+,a+n+,cmp);
  53. for(int i=;i<=n;i++){
  54. ans+=sum(n)-sum(a[i].index);
  55. add(a[i].index);
  56. }
  57. printf("%lld\n",ans);
  58. }
  59. return ;
  60. }

归并排序:

用归并排序也写了一下,复习了一下归并排序,开森。

归并排序用了二分的思想,先把一个大区间不断划分成两个小区间,知道不能划分,然后回溯的时候进行区间合并,在我们合并的时候就可以顺带求出逆序对的数量了,额,如果不会归并排序可以百度一下下。我们看下面的一个例子:

假设现在有了两个较小的排好了序的区间分别是2 6 9和 3 5 10。根据归并排序的原理,事实上他们在整个数组上面是连续的,就是

2 6 9 3 5 10这样排的,现在我们要和并他们,那么首先我们把两个区间里面最小的数字拿出来比较一下,2<3,那么2在第一个位置,然后6和3比较,6>3,那么我们要把3放在6的前面,那么我们要把3移几位呢,在连续的2 6 9 3 5 10 里面我们把3移到6前面是要经过6和9的,那么就是要移两位,那么这六个数字就变成了2 3 6 9 5 10,同理,接下来6>5,我们还是要把5移到6前面,那么还是2步,最后我们总结出一个规律,就是左边区间的a[i]和右边区间的a[j]相比较 ,如果a[i]<=a[j],那么它们本来就是从小到大的,我们不移,如果是a[i]>a[j]那么我们需要移的数目就是mid-i+1,事实上面就是左边区间剩余数字的数目。

代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<map>
  6. #include<stack>
  7. #include<cmath>
  8. #include<vector>
  9. #include<set>
  10. #include<cstdio>
  11. #include<string>
  12. #include<deque>
  13. using namespace std;
  14. typedef long long LL;
  15. #define eps 1e-8
  16. #define INF 0x3f3f3f3f
  17. #define maxn 500005
  18. LL ans,a[maxn],b[maxn],n;
  19. void marge(int left,int mid,int right){
  20. int l=left;
  21. int r=mid+;
  22. int cnt=l;
  23. while(l<=mid&&r<=right){
  24. if(a[l]<=a[r])
  25. b[cnt++]=a[l++];
  26. else{
  27. b[cnt++]=a[r++];
  28. ans+=mid-l+;//在这里加一下就可以了
  29. }
  30. }
  31. while(l<=mid) b[cnt++]=a[l++];
  32. while(r<=right) b[cnt++]=a[r++];
  33. for(int i=left;i<=right;i++)
  34. a[i]=b[i];
  35. }
  36. void marge_sort(int l,int r){
  37. if(l==r){
  38. return;
  39. }
  40. int mid=(l+r)/;
  41. marge_sort(l,mid);
  42. marge_sort(mid+,r);
  43. marge(l,mid,r);
  44. }
  45. int main()
  46. {
  47. while(scanf("%lld",&n)&&n){
  48. ans=;
  49. for(int i=;i<n;i++){
  50. scanf("%lld",&a[i]);
  51. }
  52. marge_sort(,n-);
  53. printf("%lld\n",ans);
  54. }
  55. return ;
  56. }

用归并排序或树状数组求逆序对数量 poj2299的更多相关文章

  1. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  2. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  3. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  4. 【bzoj2789】[Poi2012]Letters 树状数组求逆序对

    题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n ...

  5. “浪潮杯”第九届山东省ACM大学生程序设计竞赛(重现赛)E.sequence(树状数组求逆序对(划掉))

    传送门 E.sequence •题意 定义序列 p 中的 "good",只要 i 之前存在 pj < pi,那么,pi就是 "good": 求删除一个数, ...

  6. 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)

    2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...

  7. NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)

    对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...

  8. poj3067 Japan 树状数组求逆序对

    题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...

  9. 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)

    链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...

随机推荐

  1. findHomography(src_points, dst_points, CV_RANSAC)

    Homography,即单应性,该函数用于求src_points转换为dst_poinsts的单应性矩阵: 为了理解单应性,必须先引入透视变换的概念:把空间坐标系中的三维物体或对象转变为二维图像表示的 ...

  2. #考研笔记#计算机之word问题

    Word 问题:1. 如何为文档加密保存?单击 office 按钮\另存为\工具按钮\常规选项\设置打开文件时的密码 2. 怎样在横格稿纸中录入古诗?单击 office 按钮\新建\模板\信纸\稿纸( ...

  3. 学习笔记TF025:自编码器

    传统机器学习依赖良好的特征工程.深度学习解决有效特征难人工提取问题.无监督学习,不需要标注数据,学习数据内容组织形式,提取频繁出现特征,逐层抽象,从简单到复杂,从微观到宏观. 稀疏编码(Sparse ...

  4. Day 13 可迭代对象,迭代器对象,for循环迭代,生成器对象,枚举对象

    一.迭代器概念:# 器:包含了多个值的容器# 迭代:循环反馈(一次从容器中取出一个值)# 迭代器:从装有多个值的容器中一次取出一个值给外界# ls = 'abcdef'ls = [1, 2, 3, 4 ...

  5. C# System.IO和对文件的读写操作

      System.IO命名空间中常用的非抽象类 BinaryReader 从二进制流中读取原始数据 BinaryWriter 从二进制格式中写入原始数据 BufferedStream 字节流的临时存储 ...

  6. JDK各个版本的区别

    jdk1.5的新特性: 1. 泛型    ArrayList list=new ArrayList()------>ArrayList<Integer>list=new ArrayL ...

  7. Scrapy实战篇(三)之爬取豆瓣电影短评

    今天的主要内容是爬取豆瓣电影短评,看一下网友是怎么评价最近的电影的,方便我们以后的分析,以以下三部电影:二十二,战狼,三生三世十里桃花为例. 由于豆瓣短评网页比较简单,且不存在动态加载的内容,我们下面 ...

  8. [UE4]ProgressBar,进度条

    准备好2张进度条图片 一.新建名为“testProgress”的UserWidget,添加一个名为“ProgressBar_0”的ProgressBar到默认容器Canvas Panel 二.进度条进 ...

  9. 涨姿势:Java 分业务、分级别实现自定义日志打印

    自定义日志级别 通常的日志框架都有以下几个级别,从低到高TRACE,DEBUG,INFO,WARN,ERROR,FATAL. 默认情况,假如我们定义日志打印级别INFO,它会把大于等于INFO级别的日 ...

  10. centos 全局环境变量设置

    CentOS的环境变量配置文件体系是一个层级体系,这与其他多用户应用系统配置文件是类似的,有全局的,有用户的,有shell的,另外不同层级有时类似继承关系.下面以PATH变量为例. 1.修改/etc/ ...