题意:分配 n 个铅笔到笔筒中,每个笔筒最少放k个笔,每只铅笔有个value,同一个盒子中放入的笔的value差不能大于d,问能否找到满足条件的方案。
分析:根据题意,我们可以推出答案一定是将铅笔按 value 值排序之后划分成多个段,每个段对应一个笔筒。排完序后,为了满足条件,一个笔筒的最小 value 值铅笔在确定的情况下,这个笔筒所能装的最大 value 值的铅笔显然是一个连续的区间。那么当前铅笔可以作为新笔筒最小 value 值的条件就是 之前的铅笔已经被合法划分至若干个旧笔筒。
则我们设 dp[i] 表示 1~i 的铅笔已经被合法划分,那么下一步转移就是以第 i+1 个铅笔作为新笔筒的最小值,去找到满足条件的最大值区间并标记。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5*1E5+10;
int num[N],dp[N];
int n,k,d;
int main()
{
scanf("%d%d%d",&n,&k,&d);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
sort(num+1,num+n+1);
dp[0]=1; //初始化。
int now=1;
for(int i=0;i<=n;i++)
{
if(dp[i])
{
now=max(now,i+k); // 一个笔筒至少装 k 个
// 以当前i+1为左边界,找到最大值区间
while(now<=n&&num[now]-num[i+1]<=d)
{
dp[now]=1; // 标记
now++;
}
}
}
if(dp[n])
puts("YES");
else
puts("NO");
}