不知道这个算法对不对,就是设 fi,j 和 gi,j 分别表示 li−j 和 ri+j 能否到达,转移就是 gi→fi+1,fi→gi,状态数 O(MA)。调了好久,一直 WA ×4。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int N = 2e4 + 5;
ll n, l[N], r[N], A, B;
int m;
bool f[N][100], g[N][100];
bool check(ll a, ll b) { // 若中间无障碍,a 能否到达 b
if (a > b) return false;
if (a == b) return true;
ll len = b - a + 1;
ll cnt = (len - 1) / A;
ll L = a + cnt * A, R = a + cnt * B;
if (L <= b && R >= b) return true;
else return false;
}
int main() {
cin >> n >> m >> A >> B;
for (int i = 1; i <= m; i++) {
cin >> l[i] >> r[i];
}
if (m == 0) {
if (check(1, n)) cout << "Yes\n";
else cout << "No\n";
return 0;
}
if (A == B) {
if (A == 1) {
cout << "No\n";
return 0;
}
for (int i = 1; i <= m; i++) {
for (ll j = l[i]; j <= r[i]; j++) {
if (j % A == 1) {
cout << "No\n";
return 0;
}
}
}
if (n % A != 1) cout << "No\n";
else cout << "Yes\n";
return 0;
}
l[0] = r[0] = 0;
l[m + 1] = r[m + 1] = n + 1;
for (ll i = A + 1; i <= B + 1; i++) {
if (0 + i >= l[1]) break;
g[0][i] = true;
}
g[0][1] = true;
for (int i = 1; i <= m; i++) {
for (ll j = 1; j <= 21; j++) {
if (l[i] - j <= r[i - 1]) break;
for (ll k = 1; k <= 21; k++) {
if (r[i - 1] + k >= l[i]) break;
if (g[i - 1][k] && check(r[i - 1] + k, l[i] - j)) {
f[i][j] = true;
break;
}
}
}
for (ll j = 1; j <= 21; j++) {
if (r[i] + j >= l[i + 1]) break;
for (ll k = 1; k <= 21; k++) {
if (l[i] - k <= r[i - 1]) break;
if (f[i][k] && l[i] - k + B >= r[i] + j && l[i] - k + A <= r[i] + j) {
g[i][j] = true;
break;
}
}
}
}
for (ll i = 1; i <= 21; i++) {
if (r[m] + i > n) break;
if (g[m][i] && check(r[m] + i, n)) {
cout << "Yes\n";
return 0;
}
}
cout << "No\n";
return 0;
}