我的做法是考虑把所有不可走的段的左右两边可以走的50个点取出来。然后对于每个点往[a, b]可以走的点建边,然后对于可走段的两端的50个点,用同余最短路判断是否可达。最后dfs检查1 n是否连通
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <cmath>
#include <random>
#include <tuple>
#include <numeric>
#include <map>
#include <iomanip>
#include <cassert>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 2e4 + 5;
ll dis[25];
ll L[N], R[N];
vector<ll> Ls[N], Rs[N];
unordered_map<ll, vector<ll>> to;
unordered_map<ll, bool> ms;
bool dfs(ll u, ll tag)
{
if (u == tag) return true;
if (ms.count(u)) return ms[u];
for(auto v : to[u]) {
if (dfs(v, tag)) {
return ms[u] = true;
}
}
return ms[u] = false;
}
int main()
{
#ifdef local
freopen("in.txt", "r", stdin);
#endif // local
ios::sync_with_stdio(false);
cin.tie(0);
ll n, m, a, b;
cin >> n >> m >> a >> b;
memset(dis, 0x3f, sizeof(dis));
dis[0] = 0;
queue<int> q;
q.push(0);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = a; i <= b; i++)
{
int v = (u + i) % a;
if (dis[v] > dis[u] + i)
{
dis[v] = dis[u] + i;
q.push(v);
}
}
}
R[0] = 0;
L[m + 1] = n + 1;
for(int i = 1; i <= m; i++)
{
cin >> L[i] >> R[i];
}
for(int i = 1; i <= m; i++)
{
for(int j = L[i] - 1, z = 50; z >= 0 && j > R[i - 1]; z--, j--)
{
Ls[i].push_back(j);
}
for(int j = R[i] + 1, z = 50; z >= 0 && j < L[i + 1]; z--, j++)
{
Rs[i].push_back(j);
}
}
Rs[0].push_back(1);
Ls[m + 1].push_back(n);
for(int i = 0; i <= m; i++) {
for(auto v : Ls[i]) {
for(int w = a; w <= b; w++) {
ll now = v + w;
int mk = 0;
for(int k = max(1, i); k <= m; k++) {
if (L[k] <= now && now <= R[k]) {
mk = 1;
break;
}
if (L[k] > now) break;
}
if (!mk) {
to[v].push_back(now);
}
}
}
for(auto v : Rs[i]) {
for(int w = a; w <= b; w++) {
ll now = v + w;
int mk = 0;
for(int k = max(1, i); k <= m; k++) {
if (L[k] <= now && now <= R[k]) {
mk = 1;
break;
}
if (L[k] > now) break;
}
if (!mk) {
to[v].push_back(now);
}
}
}
for(auto u1 : Rs[i]) {
for(auto v1 : Ls[i + 1]) {
if (u1 < v1) {
ll d = v1 - u1;
if (dis[d % a] <= d) {
to[u1].push_back(v1);
}
}
}
}
}
if (dfs(1, n)) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
return 0;
}