此题很容易想到一个
O
(
N
M
2
)
O(NM^2)
O(NM2)的DP,可以过掉一半的数据。
然而我们可以通过类似完全背包的思想优化成
O
(
N
M
)
O(NM)
O(NM)。
此题细节较多,当前坐标被水管覆盖的情况下不能作为下一时刻的前驱状态,但可以作为当前时刻的前驱状态。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010, M = 1010, INF = N * M;
int n, m, k, x[N], y[N], l[N], r[N], cover[N];
inline void init() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &x[i], &y[i]);
l[i] = 1; r[i] = m;
}
for (int i = 1; i <= k; i++) {
int pos; scanf("%d", &pos);
scanf("%d%d", &l[pos], &r[pos]);
cover[pos] = true; l[pos]++; r[pos]--;
}
}
int dp[2][M], cnt, ans = INF;
inline void work() {
for (int i = 1; i <= n; i++) {
bool flag = false;
int now = i & 1, lst = now ^ 1;
memset(dp[now], 127/8, sizeof(int)*M);
for (int j = 1; j <= m; j++) {
if (j == m) {
for (int k = 0; k <= x[i]; k++)
dp[now][j] = min(dp[now][j], dp[lst][j - k] + 1);
for (int k = 1; k <= x[i]; k++)
dp[now][j] = min(dp[now][j], dp[now][j - k] + 1);
} else if (j > x[i]) {
dp[now][j] = min(dp[now][j - x[i]], dp[lst][j - x[i]]) + 1;
}
}
for (int j = l[i]; j <= r[i] && j + y[i] <= m; j++) {
dp[now][j] = min(dp[now][j], dp[lst][j + y[i]]);
}
for (int j = 0; j < l[i]; j++) dp[now][j] = INF;
for (int j = m; j > r[i]; j--) dp[now][j] = INF;
for (int j = l[i]; j <= r[i]; j++) {
if (dp[now][j] < INF) {
flag = true;
}
if (i == n) ans = min(ans, dp[now][j]);
}
if (flag) {
cnt += cover[i];
} else {
cout << "0" << endl << cnt << endl;
return;
}
}
cout << "1" << endl << ans << endl;
}
int main() {
init();
work();
return 0;
}