有个长度为(n)个数轴,数轴上标记了(0,n)以及中间的(m)个整点。你现在要在再标恰好(k)个不同的整点,最小化相邻整点间最大值-相邻整点间最小值。
(nle 10^{15},mle 4*10^5,kle n-m)
稍微转化:相当于题目给了一堆数(b_i),要给这些数进行拆分,拆分(k)次。
显然有:如果对(b_i)拆分多少次,一定是尽量均分。设(d_i)。要求(sum d_i=K=k+m+1),最小化(max lceilfrac{b_i}{d_i} ceil-min lfloor frac{b_i}{d_i} floor)。
假如已经决定了答案((L,R)),一个必要条件是:(sum lceilfrac{b_i}{R} ceille K le sum lfloor frac{b_i}{L} floor)。
于是可以二分得到(R)的下界(R_0),(L)的上界(L_0)。并且发现(L_0le R_0)。
再看另一个条件:(forall i,exist x,Lle lfloor frac{b_i}{x} floor le lceil frac{b_i}{x} ceille R)。
把((L_0,R_0))带入,得到了一些不满足限制的(i)。为了让这些(i)满足限制就需要把(L)缩小或(R)扩大。以(L)缩小为例,由(lceil frac{b_i}{x} ceille R)得(lceil frac{b_i}{R} ceille x),于是(L)缩小成(lfloor frac{b_i}{lceil frac{b_i}{R} ceil} floor)。(R)扩大同理。把这两个东西记作(l_i,r_i)。
问题变为:有个集合,集合中放着(L_0,R_0)。对这些(i),选择放(l_i)或(r_i)进入集合中。要求搞完之后集合中的极差最小。
贪心:先全部选(l_i),对(l_i)排序,每次把(l_i)换出来把(r_i)丢进去。
时间(O(mlg m))。
using namespace std;
#include <bits/stdc++.h>
#define M 400005
#define ll long long
#define du(x,y) (((x)+(y)-1)/(y))
ll n,k;
int m;
ll a[M],b[M];
ll L0,R0;
void init(){
L0=R0=-1;
ll l=1,r=n;
while (l<=r){
ll mid=l+r>>1,s=0;
for (int i=0;i<=m;++i)
s+=du(b[i],mid)-1;
if (s<=k)
r=(R0=mid)-1;
else
l=mid+1;
}
l=1,r=n;
while (l<=r){
ll mid=l+r>>1,s=0;
bool bz=1;
for (int i=0;i<=m && bz;++i){
if (b[i]/mid==0)
bz=0;
s+=b[i]/mid-1;
}
if (bz && s>=k)
l=(L0=mid)+1;
else
r=mid-1;
}
// assert(L0!=-1 && R0!=-1);
}
pair<ll,ll> p[M];
multiset<ll> s;
int main(){
freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while (T--){
scanf("%lld%d%lld",&n,&m,&k);
for (int i=1;i<=m;++i)
scanf("%lld",&a[i]);
a[m+1]=n;
for (int i=0;i<=m;++i)
b[i]=a[i+1]-a[i];
init();
ll ans;
assert(L0<=R0);
bool bz=1;
for (int i=0;i<=m;++i)
bz&=((b[i]+R0-1)/R0<=b[i]/L0);
if (bz)
ans=R0-L0;
else{
s.clear();
s.insert(L0),s.insert(R0);
int k=0;
for (int i=0;i<=m;++i)
if (du(b[i],R0)>b[i]/L0){
p[++k]={b[i]/du(b[i],R0),du(b[i],b[i]/L0)};
s.insert(p[k].first);
}
sort(p+1,p+k+1);
ans=*s.rbegin()-*s.begin();
for (int i=1;i<=k;++i){
s.erase(s.find(p[i].first));
s.insert(p[i].second);
ans=min(ans,*s.rbegin()-*s.begin());
}
}
printf("%lld
",ans);
}
return 0;
}