Codeforces 985E

题意略。

思路:

这个题目开始想的有点暴力,后来发现有搜索的性质,因此转而用动态规划。首先,我们要把这些数排个序。

定义状态: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
*/

猜你喜欢

转载自www.cnblogs.com/tiberius/p/9162380.html