计蒜客 T2021 飞扬的小鸟

题目链接:计蒜客 T2021 飞扬的小鸟

题目大意:
计蒜客 T2021 飞扬的小鸟

题解:
按照横坐标从左往右递推,设\(dp[i][j]\)为到达点\((i,j)\)所需的最小点击次数。
状态转移方程:

\[dp[i][j] = min\{dp[i][j], dp[i - 1][j - x[i]] + 1, dp[i][j-x[i]] + 1\} \]

\[dp[i][j] = min\{dp[i][j], dp[i - 1][j + y[i]]\} \]

因为触顶之后不会再上升,所以\(dp[i][m] = min\{dp[i][k],m\leq k \leq m+x[i]\}\)。
如果所在的点有管道,则\(dp[i][j]=0\)。

#include <cstring>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10010
#define M 2010

int n, m, p, x[N], y[N], low[N], high[N], dp[N][M], ans;
bool vis[N];

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m >> p;
    for (int i = 1; i <= n; ++i) {
        cin >> x[i] >> y[i];
    }
    for (int i = 1; i <= n; ++i) {
        low[i] = 1, high[i] = m;
    }
    for (int i = 1, k, l, h; i <= p; ++i) {
        cin >> k >> l >> h;
        vis[k] = true;
        low[k] = l + 1;
        high[k] = h - 1;
    }
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 1; i <= m; ++i) {
        dp[0][i] = 0;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = x[i] + 1; j <= m + x[i]; ++j) {
            dp[i][j] = min(dp[i][j], min(dp[i - 1][j - x[i]] + 1, dp[i][j - x[i]] + 1));
        }
        for (int j = m + 1; j <= m + x[i]; ++j) {
            dp[i][m] = min(dp[i][m], dp[i][j]);
        }
        for (int j = 1; j <= m - y[i]; ++j) {
            dp[i][j] = min(dp[i][j], dp[i - 1][j + y[i]]);
        }
        for (int j = 1; j < low[i]; ++j) {
            dp[i][j] = dp[0][0];
        }
        for (int j = high[i] + 1; j <= m; ++j) {
            dp[i][j] = dp[0][0];
        }
    }
    ans = INF;
    for (int i = 1; i <= m; ++i) {
        ans = min(ans, dp[n][i]);
    }
    if (ans < INF) {
        cout << 1 << endl << ans << endl;
    } else {
        int i, j;
        for (i = n; i >= 1; --i) {
            for (j = 1; j <= m; ++j) {
                if (dp[i][j] < INF) {
                    break;
                }
            }
            if (j <= m) {
                break;
            }
        }
        ans = 0;
        for (j = 1; j <= i; ++j) {
            if (vis[j]) {
                ans++;
            }
        }
        cout << 0 << endl << ans << endl;
    }
    return 0;
}
上一篇:分页的实现| 学习笔记


下一篇:刷题-栈和队列(2)