原题传送门
先排个序
最大值最小,用二分
然后用dp验证
d
p
i
dp_i
dpi表示当前到
i
i
i,最后一个分组是否可以以
i
i
i结尾
d
p
i
∣
=
d
p
j
−
1
(
j
<
i
,
a
i
−
a
j
<
=
m
i
d
)
dp_i|=dp_{j-1}(j<i,a_i-a_j<=mid)
dpi∣=dpj−1(j<i,ai−aj<=mid)
但是这个是
O
(
n
2
)
O(n^2)
O(n2)的,可以优化
发现对于一对
(
i
,
j
)
(
i
>
j
)
(i,j)(i>j)
(i,j)(i>j),若
[
j
,
i
]
[j,i]
[j,i]无法分成一个组,那么
[
j
,
i
+
1
]
[j,i+1]
[j,i+1]一定也无法分成一组
可以把枚举
j
j
j的部分改成指针
l
l
l表示最小的可能转化给
i
i
i的,
r
=
i
−
m
+
1
r=i-m+1
r=i−m+1
每次如果
d
p
l
−
1
=
0
,
+
+
l
dp_{l-1}=0,++l
dpl−1=0,++l
Code:
#include <bits/stdc++.h>
#define maxn 300010
#define LL long long
using namespace std;
int a[maxn], dp[maxn], n, m;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool check(int mid){
dp[0] = 1;
int l = 1, r;
for (int i = 1; i <= n; ++i){
dp[i] = 0;
while (a[i] - a[l] > mid) ++l;
r = i - m + 1;
for (int j = l; j <= r; ++j, ++l)
if (dp[j - 1]){ dp[i] = 1; break; }
}
return dp[n];
}
int main(){
n = read(), m = read();
if (m == 1) return puts("0"), 0;
for (int i = 1; i <= n; ++i) a[i] = read();
sort(a + 1, a + 1 + n);
int l = 0, r = a[n] - a[1], ans = 0;
while (l <= r){
int mid = (l + r) >> 1;
if (check(mid)) r = mid - 1, ans = mid; else l = mid + 1;
}
printf("%d\n", ans);
return 0;
}