当前位置: 代码迷 >> 综合 >> 『DP·单调队列』CodeForces - 985E Pencils and Boxes
  详细解决方案

『DP·单调队列』CodeForces - 985E Pencils and Boxes

热度:25   发布时间:2023-12-17 10:58:45.0

P r o b l e m \mathrm{Problem} Problem

在这里插入图片描述
纠正luogu的一个mistake:是 ∣ a i ? a j ∣ ≤ d . |a_i-a_j|\le d. ai??aj?d.

S o l u t i o n \mathrm{Solution} Solution

我们可以采用DP的思想,设 f [ i ] f[i] f[i]表示到 i i i为止分成若干组的可行性。

显然我们可以通过排序,想原来的序列分成连续的几段。

那么就有: f [ i ] ∣ = f [ j ] ( i ? j < k 且 a i ? a j + 1 ≤ d ) f[i]|=f[j](i-j<k且a_i-a_{j+1}\le d) f[i]=f[j](i?j<kai??aj+1?d)

我们来考虑一下如何快速的解决这些限制。

由于数据元素单调递增,因此我们可以来维护一个单调队列。

  • 对于限制 i ? j < k i-j<k i?j<k来说,只要满足 f [ i ? k ] = 1 f[i-k]=1 f[i?k]=1就将 i ? k + 1 i-k+1 i?k+1加入队列。
  • 弹出首位差值过大的队头,直到满足条件位置,即 a [ i ] ? a [ f r o n t ] ≤ d a[i]-a[\mathrm{front}]\le d a[i]?a[front]d为止。

代码如下:

#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>using namespace std;
const int N = 6e5;int n, m, k, d;
int a[N], f[N];queue<int>q;int read(void)
{
    int s = 0, w = 0; char c = getchar();while (c < '0' || c > '9') w |= c == '-', c = getchar();while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();return w ? -s : s;
}int main(void)
{
    n = read(), k = read(), d = read();for (int i=1;i<=n;++i) a[i] = read();sort(a+1,a+n+1);f[0] = 1;for (int i=k;i<=n;++i){
    if (f[i-k]) q.push(i-k+1);while (q.size() && a[i]-a[q.front()] > d) q.pop();f[i] = !q.empty();}puts(f[n] ? "YES" : "NO");return 0;
}