思路:二分答案区间,难点在判断上,因为是要求最小值,所以为了得到最优解,我们要先将a数组排序,这样我们从中选择连续的一段一段作为一组这样得到的最小差值才是我们的最优解。我们思路上这样理解:我们从左往右进行分组,设pos=i表示[1~i]的人可以进行分组,开始先判断第一个区间,第一个区间左端点显然为1,枚举所有区间右端点的所有可能点(判断方程为a[m+i]-a[1]<=mid,右端点为m+i),对于每一种可能的点,我们继续往后判断是否可以进行分组,这时不在考虑它之前的状态考虑它后面一个点作为左区间,判断它可能的所有右区间,一直到判断区间时,左端点达到最右边。
如果[1,i]的人可以进行分组,那么在对后面考虑时我们就不在考虑它,在对它后面[i+1,i+m+k]的区间进行考虑i+m+k为最后一个满足a[i+m+k]-a[i+1]<=mid的数,如果一个区间右边的数满足a[i+m+k]-a[i+1]<=mid,证明这个也可以进行分组,状态pos直接转移到i+m+k。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int vis[maxn];
int a[maxn];
int n,m;
bool dfs(int pos,int mid)
{
if(vis[pos]==0)
vis[pos]=1;
else
return false;
if(pos==n)
return true;
for(int i=0; pos+m+i<=n&&a[pos+m+i]-a[pos+1]<=mid; i++)
{
if(dfs(pos+m+i,mid))
return true;
}
return false;
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
cin>>a[i];
sort(a+1,a+1+n);
int l,r;
l=0;
r=1e9;
while(l<r)
{
memset(vis,0,sizeof(vis));
int mid=(l+r)/2;
// printf("mid=%d l=%d r=%d
",mid,l,r);
if(dfs(0,mid))
r=mid;
else
l=mid+1;
}
cout<<l;
}