题意略。
思路:
这个题目开始想的有点暴力,后来发现有搜索的性质,因此转而用动态规划。首先,我们要把这些数排个序。
定义状态:dp[i]为排序后i~n能否成功打包,1表示可以,0表示不能打包。
状态转移方程:dp[i] = max{dp[j]} (i + k <= j <= upper)upper为在有序数组中,第一个比当前值store[i] + d大的数的下标。
为了防止它卡数据,这里可以用单调队列优化一下,由于确定upper要使用二分搜索,所以总的复杂度是O(nlogn)。
详见代码:
#include<bits/stdc++.h> #define maxn 500005 using namespace std; int dp[maxn],que[maxn],head,tail,store[maxn]; int n,k,d; int main(){ scanf("%d%d%d",&n,&k,&d); for(int i = 1;i <= n;++i) scanf("%d",&store[i]); sort(store + 1,store + 1 + n); dp[n + 1] = 1; for(int i = n;i >= 1;--i){ int temp = store[i] + d; int r = upper_bound(store + 1,store + 1 + n,temp) - store; int l = i + k; if(l > r){ dp[i] = 0; } else{ while(que[head] > r && head < tail) ++head; while(head < tail && dp[que[tail - 1]] < dp[l]) --tail; que[tail++] = l; dp[i] = dp[que[head]]; } } printf("%s\n",dp[1] ? "YES" : "NO"); return 0; } /* 18 3 1 1 1 1 2 2 3 5 5 5 6 6 7 9 9 9 10 10 11 YES */