Description

一个数组,要求先对前n个数字排序(以方便后续操作);又要求对前n+i个数字排序;又要求对前n+j … 前n+k个数字排序(i、j、k的大小远小于n,且i、j、k间没有大小关系)。总之就是对一个不定的范围内数据要进行频繁的按大小顺序调用,但是这个范围边界变化不大,很多数据重叠,这样每次都对此次区间内数据排序,频繁排序的话很费时间。

例如一个数组{1,3,6,5,2,4,1,9,0},一共9个数字,下标0~8。要求:

每次取一个区间,计算区间内(最大值−最小值)2+(次大值−次小值)2+(次次大值−次次小值)2+...的值。很容易想到对区间排个序,即可方便获得最大、次大值等。

对1~5排序:{2,3,4,5,6}

对1~6排序:{1,2,3,4,5,6}

对2~5排序:{2,4,5,6}

可以看出2、5、6始终在范围内,但每次都要针对所选区间重新排序,很麻烦。

既然大部分数据一直出现在范围内,现在就希望能够一次排序,应对所有情况。

Key

继续使用上述的例子:Array={1,3,6,5,2,4,1,9,0}

开个新数组作其索引:Index={0,1,2,3,4,5,6,7,8}

令索引数组按照Array的大小关系排序,得Index={8,0,6,4,1,5,3,2,7}

对于区间[1, 5]:从左向右找出第一个在[1, 5]的下标即为最小值:8不符合、0不符合、6不符合,4符合,那么最小值就是Array[4]=2,次大值就是Array[1]=3 …

即每次只需检测排序后当前位的数字的下标是否在该区间内即可。

Sample

题目:https://hihocoder.com/problemset/problem/1384

一道贪心的题,期间需要对下标i到j、i到j+k之间的数字分别排序。是别人家的代码(他的原文链接,虽然我也不知道他是不是转别人的),就是在这学到的技巧。注意观察judge函数与judge2函数的差异,judge2函数即实现了上述排序思想。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <cmath>
  6. using namespace std;
  7. typedef long long int ll;
  8. ll m,n,k;
  9. ll a[500050];
  10. ll b[500050];
  11. int cnt=0;
  12. inline bool cmp(int x,int y)
  13. {
  14. return a[x]<a[y];
  15. }
  16. bool judge(int l,int r)
  17. {
  18. int pos=0;
  19. while(l+pos<=r)b[pos]=a[l+pos],pos++;
  20. sort(b,b+pos);
  21. pos--;
  22. int mid=(pos-1)/2;
  23. ll res=0;
  24. for(int i=0; i<=mid&&i<m; i++)
  25. {
  26. res+=(b[i]-b[pos-i])*(b[i]-b[pos-i]);
  27. if(res>k)
  28. return false;
  29. }
  30. return res<=k;
  31. }
  32. void init(int l,int r)
  33. {
  34. cnt=0;
  35. for(int i=l; i<=r; i++)b[cnt++]=i;
  36. sort(b,b+cnt,cmp);
  37. }
  38. bool judge2(int r)
  39. {
  40. int i,j,kk;
  41. ll res=0;
  42. for(i=0,j=cnt-1,kk=m; kk; i++,j--,kk--)
  43. {
  44. while(i<j&&b[i]>r)i++;
  45. while(i<j&&b[j]>r)j--;
  46. if(i>=j)break;
  47. res+=(a[b[i]]-a[b[j]])*(a[b[i]]-a[b[j]]);
  48. if(res>k)break;
  49. }
  50. return res<=k;
  51. }
  52. int main()
  53. {
  54. int T;
  55. scanf("%d",&T);
  56. while(T--)
  57. {
  58. scanf("%lld%lld%lld",&n,&m,&k);
  59. for(int i=0; i<n; i++)
  60. scanf("%lld",&a[i]);
  61. int ans=0;
  62. int l=0;
  63. while(l<n)
  64. {
  65. int kk=1;
  66. while(kk+l<n&&judge(l,l+kk))
  67. kk*=2;
  68. int first=l+kk/2,last=l+kk-1<n?l+kk-1:n-1;
  69. init(l,last);
  70. int mid;
  71. int pos=l;
  72. while(first<=last)
  73. {
  74. if(judge2(mid=(first+last)/2))
  75. {
  76. first=mid+1;
  77. pos=mid;
  78. }
  79. else
  80. last=mid-1;
  81. }
  82. l=pos+1;
  83. ans++;
  84. }
  85. cout<<ans<<endl;
  86. }
  87. return 0;
  88. }

[笔记]ACM笔记 - 排序小技巧的更多相关文章

  1. ACM 刷题小技巧【转】

    转载自URl-team ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 大数据输入输出时最好 ...

  2. HTML+CSS笔记 CSS中级 一些小技巧

    水平居中 行内元素的水平居中 </a></li> <li><a href="#">2</a></li> &l ...

  3. [笔记]ACM笔记 - 利用FFT求卷积(求多项式乘法)

    卷积 给定向量:, 向量和: 数量积(内积.点积): 卷积:,其中 例如: 卷积的最典型的应用就是多项式乘法(多项式乘法就是求卷积).以下就用多项式乘法来描述.举例卷积与DFT. 关于多项式 对于多项 ...

  4. [笔记]ACM笔记 - 组合数

    一.高中数学公式复习 , (好吧这个没学过但是既然看到了就一并抄过来了) 二.快速求组合数取模C(n, m)%p 当n和p大小不同时方法有不同. 1. n很小,p随意,p不需要为素数 1) 原理 使用 ...

  5. [笔记]ACM笔记 - 自用模板

    长期更新. 快速幂 lld pow_mod(lld a, lld b, const int &pr) { lld ans = 1; while (b) { if (b & 1) ans ...

  6. HTML+CSS笔记 CSS笔记集合

    HTML+CSS笔记 表格,超链接,图片,表单 涉及内容:表格,超链接,图片,表单 HTML+CSS笔记 CSS入门 涉及内容:简介,优势,语法说明,代码注释,CSS样式位置,不同样式优先级,选择器, ...

  7. lua学习笔记11:lua中的小技巧

    lua中的小技巧,即基础lua语言本身的特种,进行一个些简化的操作 一. 巧用or x = x or v 等价于: if not x then x = v end 假设x为nil或false,就给他赋 ...

  8. ACM 做题过程中的一些小技巧。

    ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...

  9. 《Algorithm算法》笔记:元素排序(2)——希尔排序

    <Algorithm算法>笔记:元素排序(2)——希尔排序 Algorithm算法笔记元素排序2希尔排序 希尔排序思想 为什么是插入排序 h的确定方法 希尔排序的特点 代码 有关排序的介绍 ...

随机推荐

  1. MySQL 查询重复的数据,以及部分字段去重和完全去重

    1.查找表中多余的重复记录(多个字段) select * from vitae a where (a.peopleId,a.seq) in  (select peopleId,seq from vit ...

  2. windows 安装Beautiful Soup(转)

    Beautiful Soup是一个Python的一个库,主要为一些短周期项目比如屏幕抓取而设计.有三个特性使得它非常强大: 1.Beautiful Soup提供了一些简单的方法和Python术语,用于 ...

  3. AP模块发票过账标记为否检查方法

    根据发票编号,查找发票 : 发票过账标记,始终为否,创建会计科目提示如下: 

  4. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(二) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 前: ...

  5. css2.1实现圆角边框

    虽然css3的border-radius实现圆角很简单,但是我还是认为css2.1中好多技术还是很值得学习的,我也是后来才知道这就是传说中的滑动门技术.脑洞大开啊 附上demo <!DOCTYP ...

  6. 【C++】模拟实现auto_ptr

    看了<Effctive C++>,里面提到用对象去管理资源,可以有效防止内存泄漏. 结合auto_ptr特性,稍微思考了一下,实现了一个简单的auto_ptr (因为代码量小,就不分文件了 ...

  7. 重温Javascript(二)

    对象 可以想象成散列表,键值对,值可以是数据或函数 创建对象的方式 1.工厂模式 function createPerson(name, age, job){ var o = new Object() ...

  8. 采用Spring AOP+Log4j记录项目日志

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...

  9. js动弹特效

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. Git与Github的使用学习

    摘要 本文讲解下Git的使用,包括使用Git上传项目工程到Github,文末有彩蛋哦. 1.安装Git 使用apt-get安 sudo apt-get update sudo apt-get inst ...