思路:如果 a=b,则至少 400 次后,一定有连续的 20 个位置可以到达。最坏情况:a=19,b=20,初始时在第 1 个,则第 381∼400 个连续格子都可到达。
使用小根堆维护当前可以到的位置,对 li−ri−1 的大小分类讨论,最后判断到达 n。
#include <bits/stdc++.h>
#ifndef ONLINE_JUDGE
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
using namespace std;
using namespace chrono;
typedef long long i64;
constexpr int N(2e4 + 5);
int m, a, b;
i64 n, l[N], r[N];
priority_queue<i64, vector<i64>, greater<i64>> q;
int main() {
int i, j;
i64 f;
scanf("%lld%d%d%d", &n, &m, &a, &b);
if (a == b) {
for (i = 1; i <= m; ++i) {
scanf("%lld%lld", l + i, r + i);
f = l[i] / a * a + 1;
if (f < l[i]) {
f += a;
}
if (l[i] <= f && f <= r[i]) {
puts("No");
return 0;
}
}
puts("Yes");
return 0;
}
q.push(1);
for (i = 1; i <= m; ++i) {
scanf("%lld%lld", l + i, r + i);
if (q.empty() || r[i] - l[i] + 1 >= b) {
puts("No");
return 0;
}
if (l[i] - r[i - 1] >= 500) {
while (q.size()) {
q.pop();
}
for (j = a; j <= b; ++j) {
if (l[i] - 1 + j > r[i]) {
q.push(l[i] - 1 + j);
}
}
} else {
while (true) {
while (q.size() && l[i] <= q.top() && q.top() <= r[i]) {
q.pop();
}
if (q.empty() || q.top() > r[i]) {
break;
}
f = q.top();
q.pop();
while (q.size() && q.top() == f) {
q.pop();
}
for (j = a; j <= b; ++j) {
if (f + j < l[i] || f + j > r[i]) {
q.push(f + j);
}
}
}
}
}
if (n - r[m] <= 500) {
while (q.size() && q.top() < n) {
f = q.top();
q.pop();
while (q.size() && q.top() == f) {
q.pop();
}
for (j = a; j <= b; ++j) {
if (f + j <= n) {
q.push(f + j);
}
}
}
puts(q.size() && q.top() == n ? "Yes" : "No");
} else {
puts("Yes");
}
return 0;
}