由于相差不超过k才可以放在一起,要判断不超过k这个条件,显然我们需要排序

首先我们需要一个f数组,f[i]意义看代码开头注释,

假设我们可以选择的某一个区间是a[l]~a[r](已排序且最优(最长的意思)),那么这个区间要符合这样一个性质:

a[r]-a[l]<=k

移项一下,

a[r]<=k+a[l](r要尽可能大)

而a[l]中的l我们是枚举得到的,因此我们只需要求出对应的r即可

我们观察移项后的式子可以发现,我们要求的r其实是数列中小于等于k+a[l]的最大值

那么这显然是符合可二分性的,

所以我们二分查找r的位置,由此可以得到f[l]=half(k+a[l]) - l + 1;

然后我们可以枚举第一个架子放的是从哪里开始的

因为不允许重叠,因此我们需要查询f[f[i]+i]~f[n]的最大值(第二个架子),

为什么不用查询前面的?

与枚举数对同理,如果足够优的话,前面的会查询到后面的,所以不必重复查询(而且也不好处理,因为不知道前面查询到的会不会和后面冲突),

那么区间查询最大值,无修改,我们可以想到什么呢?

ST表!

那么ST表是什么?

ST[i][j]存从i开始往后面2^j个(包括i自己)的最大值

根据倍增的思想,我们可以在nlogn的时间内建出ST表

然后再次根据倍增的思想,我们可以实现O(1)查询

这里ST表就不作过多解释了,还不会的去写模板ST表即可

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 50020
/*二分查找f[i],以i为开头最多能放几个,然后对f数组建立ST表,
查询f[f[i]+i] ~ f[n]的最大值,
为什么不用查询前面的?
与枚举数对同理,如果足够优的话,前面的会查询到后面的,所以不必重复查询(而且也不好处理),
这样的话,时间复杂度O(nlogn(获取f数组) + nlogn(获取ST表) + n(查询))
O(nlogn+n)? --- > O(nlogn)*/
int n,ans,k;
int ST[AC][],f[AC],a[AC],p[AC];
inline int read()
{
int x=;char c=getchar();
while(c>'' || c<'') c=getchar();
while(c>='' && c<='') x=x*+c-'',c=getchar();
return x;
} inline void upmax(int &a,int b)
{
if(b>a) a=b;
} inline int Min(int a,int b)
{
if(a<b) return a;
else return b;
} inline int Max(int a,int b)
{
if(a>b) return a;
else return b;
} inline int half(int x)//二分查找小于等于x的最大值,并返回下标
{
int l=,r=n,mid;
while(l<r)
{
mid=(l+r+)>>;//由于符合条件时应尽可能向右移,这时为了保持ans在区间内,
//---> l=mid,但这样的话,由于传统mid偏向l,将会导致死循环
//因此将mid手动偏向r,这时由于不符合才会移动r,所以--->r=mid-1,本就不需要mid,
//因此每次转移必定会有偏移量,所以就不会死循环了
if(a[mid] <= x) l=mid;//由于mid偏向l,所以+1防止死循环
else r=mid-;
}
return l;
} void pre()
{
n=read(),k=read();
for(R i=;i<=n;i++) a[i]=read();
sort(a+,a+n+);
for(R i=;i<=n;i++) f[i]=half(k+a[i]) - i + ;//f[i]存个数
} void built()
{
int key=;
for(R i=;i<=n;i++)
{
if(i==(key<<)) p[i]=p[i-]+,key<<=;
else p[i]=p[i-];//存下长度为i时,最长包含2的几次方,以保证一定包含了整个区间
ST[i][]=f[i];
}
for(R j=;j<=;j++)
for(R i=;i<=n;i++)
ST[i][j]=Max(ST[i][j-] , ST[Min(i + ( << (j - )),n)][j-]);//因为可能剩下的i~n,根本就不够1<<j,所以要取Min
} void work()
{
for(R i=;i<=n;i++)
{
int l=f[i] + i,r=n;
k=p[r-l+];
upmax(ans,f[i] + Max(ST[l][k],ST[r - (<<k) +][k]));
}
printf("%d\n",ans);
} int main()
{
freopen("in.in","r",stdin);
pre();
built();
work();
fclose(stdin);
return ;
}

最新文章

  1. Linux 之 GCC 和 GDB
  2. Swift3.0P1 语法指南——基本操作符
  3. atitit.查看预编译sql问号 本质and原理and查看原生sql语句
  4. Leetcode: Range Sum Query 2D - Mutable &amp;&amp; Summary: Binary Indexed Tree
  5. Java基础(38):Calendar类的应用(优于Date类)
  6. 关于 error: LNK1123: failure during conversion to COFF: file invalid or corrupt 错误的解决方案【Qt】【 VS2010】
  7. Unity3D C#脚本开发学习
  8. JavaScript 函数之 ------------------ 闭包
  9. UVA 507 - Jill Rides Again 动态规划
  10. linux脚本Shell之awk详解(二)
  11. python基础之数据类型与变量
  12. 华为模拟器eNSP安装(最新)网络工程师必备!
  13. arrow function and bind
  14. 第45章:MongoDB-集群--Sharding(分片)--分片的管理
  15. PYTHON- 操作系统和python程序
  16. Cesium 实践
  17. (网页)JS编程中,有时需要在一个方法返回两个个或两个以上的数据
  18. java.sql.SQLSyntaxErrorException: ORA-00904: &quot;column&quot;: 标识符无效
  19. Centos 7 开放查看端口 防火墙关闭打开
  20. oracle中动态SQL使用详细介绍

热门文章

  1. 9、Java ConcurrentModificationException异常原因和解决方法
  2. 关于iOS开发的各种证书
  3. C#调用大漠插件,发送QQ和微信消息
  4. java 浅复制 深复制
  5. python3基础盲点
  6. 利用JSON Schema校验JSON数据格式
  7. 初学Direct X(3)
  8. JS实现对数组的去重
  9. github项目切换远程https到ssh通道
  10. [Clr via C#读书笔记]Cp19可空值类型