CF985E Solution
题解
dp+双指针,时间复杂度为\(O(n)\)。
状态:\(dp[i]\):当前最右区间结尾为\(i\)时是/否(\(1/0\))可行。
初始值:\(dp[0]=1,dp[i]=0\quad(1\le i\le n)\)
转移方程:将\(a\)数组升序排序,设\(dp[i-1]\)由\(dp[lst]\)转移而来。
\[dp[i]|=dp[j]\&(a_i-a_{j+1}\le d) \quad (1\le i\le n,lst\le j\le i-k)
\]
因为\(a_i-a_{j+1}\)(排序后\(a_i,a_{j+1}\)分别为\([a_{j+1},a_i]\)的最大,最小值)随\(j\)增大单调递减,而\(dp[j]\)不变,所以\(j\)仅会右移。
目标状态:\(dp[n]\)
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int a[N]; bool dp[N];
int main()
{
int n,k,d,lst=0;
scanf("%d%d%d",&n,&k,&d);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=lst;j<=i-k;j++)
{
if(dp[j]&(a[i]-a[j+1]<=d)) {dp[i]=1,lst=j; break;}
if(j==i-k) lst=i-k+1;
}
}
if(dp[n]) printf("YES");
else printf("NO");
return 0;
}