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函数即实现了上述排序思想。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long int ll;
ll m,n,k;
ll a[500050];
ll b[500050];
int cnt=0;
inline bool cmp(int x,int y)
{
return a[x]<a[y];
}
bool judge(int l,int r)
{
int pos=0;
while(l+pos<=r)b[pos]=a[l+pos],pos++;
sort(b,b+pos);
pos--;
int mid=(pos-1)/2;
ll res=0;
for(int i=0; i<=mid&&i<m; i++)
{
res+=(b[i]-b[pos-i])*(b[i]-b[pos-i]);
if(res>k)
return false;
}
return res<=k;
}
void init(int l,int r)
{
cnt=0;
for(int i=l; i<=r; i++)b[cnt++]=i;
sort(b,b+cnt,cmp);
}
bool judge2(int r)
{
int i,j,kk;
ll res=0;
for(i=0,j=cnt-1,kk=m; kk; i++,j--,kk--)
{
while(i<j&&b[i]>r)i++;
while(i<j&&b[j]>r)j--;
if(i>=j)break;
res+=(a[b[i]]-a[b[j]])*(a[b[i]]-a[b[j]]);
if(res>k)break;
}
return res<=k;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=0; i<n; i++)
scanf("%lld",&a[i]);
int ans=0;
int l=0;
while(l<n)
{
int kk=1;
while(kk+l<n&&judge(l,l+kk))
kk*=2;
int first=l+kk/2,last=l+kk-1<n?l+kk-1:n-1;
init(l,last);
int mid;
int pos=l;
while(first<=last)
{
if(judge2(mid=(first+last)/2))
{
first=mid+1;
pos=mid;
}
else
last=mid-1;
}
l=pos+1;
ans++;
}
cout<<ans<<endl;
}
return 0;
}

最新文章

  1. 15天玩转redis —— 第九篇 发布/订阅模式
  2. php查询文件扩展名
  3. 淘宝上倒卖新浪微盘事件来龙去脉——谈谈巧用IMEI
  4. 转载:python发送HTTP请求
  5. (九)串行口方式0 拓展并行输入端口 74LS165 芯片
  6. Andriod Studio科学文章——4.常见问题解答有关编译
  7. poj 1321 棋盘问题 递归运算
  8. QRadionButton 圆点样式
  9. 安装SQL Server 2005 - 初学者系列 - 学习者系列文章
  10. 嵌入式C实战项目开发技巧:如果对一个有规律的数组表进行位移操作
  11. CC1310 笔记
  12. dell T130服务器加内存
  13. css横线中间放图片或者文字
  14. 654. Maximum Binary Tree
  15. kafka7 探索生产者同步or异步发送消息
  16. PX Deq: Execution Msg 等待事件
  17. 【Java框架型项目从入门到装逼】第十一节 用户新增之把数据传递到后台
  18. BugkuCTF ---游戏过关 writeup
  19. Patch multi versions of windows via Power shell
  20. Chem 3D模型的参数值更改方法

热门文章

  1. Python注释用法
  2. Jenkis Editable Email Notification Plugin 使用介绍
  3. 维护Study
  4. 【VB超简单入门】六、基本数据类型
  5. PyQt通过resize改变窗体大小时ListWidget显示异常
  6. 关于ng-class的用法
  7. JavaScript基础学习(四)&mdash;Object
  8. 移植 DeepinQQ 到 Fedora 中
  9. JavaScript Break 和 Continue 语句
  10. Java与面向对象之随感(2)