
P1941 [NOIP 2014 提高组] 飞扬的小鸟 题解
就从可能走到这个位置上的所有点转移过来,取一个最小值,不过如果是从下面飞上来的话答案需要再加一。所以,本蒟蒻就用了一个简简单单轻轻松松就能理解的小 dp。因此,我们只需要分成四种情况讨论即可,每走到一个位置。作为一名蒟蒻,默默地展开了算法标签,发现是 dp。那么小鸟还可能从某个点向下掉,同上。呢(假设地图无边界限制)?所使用的最小屏幕点击数。那我们可以从哪些坐标走到。小鸟从某个点向上飞到了。
·
解题思路
作为一名蒟蒻,默默地展开了算法标签,发现是 dp。
所以,本蒟蒻就用了一个简简单单轻轻松松就能理解的小 dp。
很容易想到我们设 d p i , j dp_{i,j} dpi,j 为走到 ( x , y ) (x, y) (x,y) 所使用的最小屏幕点击数。
那我们可以从哪些坐标走到 ( i , j ) (i, j) (i,j) 呢(假设地图无边界限制)?
我们先看第一种情况:
小鸟从某个点向上飞到了 ( i , j ) (i, j) (i,j)。
- 从 ( i , j − x i ) (i, j - x_i) (i,j−xi) 走到 ( i , j ) (i, j) (i,j),即小鸟飞到 ( i , j − x i ) (i, j - x_i) (i,j−xi) 时,玩家点击了屏幕一次,然后小鸟就飞到了 ( i , j − x i ) (i, j - x_i) (i,j−xi)。(玩家连续点击的情况)
- 从 ( i − 1 , j − x i ) (i - 1, j - x_i) (i−1,j−xi) 走到 ( i , j ) (i, j) (i,j),即小鸟飞到 ( i − 1 , j − x i ) (i - 1, j - x_i) (i−1,j−xi) 时,玩家点击了屏幕一次,然后小鸟就向右飞了一个单位长度,又向上飞了 x i x_i xi 个单位长度,最后到达了 ( i − 1 + 1 , j − x i + x i ) (i - 1 + 1, j - x_i + x_i) (i−1+1,j−xi+xi) 即 ( i , j ) (i, j) (i,j)。
那么小鸟还可能从某个点向下掉,同上。
因此,我们只需要分成四种情况讨论即可,每走到一个位置 ( i , j ) (i,j) (i,j), d p i , j dp_{i,j} dpi,j 就从可能走到这个位置上的所有点转移过来,取一个最小值,不过如果是从下面飞上来的话答案需要再加一。
CODE:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int x[10010], y[10010];
int dp[2][2010];
unordered_map<short, pair<int, int> > f;
signed main() {
ios::sync_with_stdio(false);
ios_base::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
}
for (int i = 1; i <= k; i++) {
int p, l, h;
cin >> p >> l >> h;
f[p] = make_pair(l, h);
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
dp[i & 1][j] = 1e18;
}
for (int j = x[i] + 1; j <= x[i] + m; j++) {
//i & 1 ^ 1 相当于 i = 0 时取 1,i = 1 取 i = 0
//与 i - 1 差不多的意思,只不过 0 - 1 = 1
dp[i & 1][j] = min(dp[i & 1 ^ 1][j - x[i]], dp[i & 1][j - x[i]]) + 1;
}
for (int j = m + 1; j <= x[i] + m; j++) { //大于 m 的位置全都看成到达 m
dp[i & 1][m] = min(dp[i & 1][m], dp[i & 1][j]);
}
for (int j = 1; j <= m - y[i]; j++) {
dp[i & 1][j] = min(dp[i & 1][j], dp[i & 1 ^ 1][j + y[i]]);
}
if (f.count(i)) {
bool flag = false;
for (int j = 0; j <= m; j++) {
if (j <= f[i].first || j >= f[i].second) {
dp[i & 1][j] = 1e18;
} else {
if (dp[i & 1][j] != 1e18) {
flag = true;
}
}
}
if (!flag) {
cout << "0\n" << cnt;
return 0;
}
cnt++;
}
}
int ans = 1e18;
for (int i = 0; i <= m; i++) {
ans = min(dp[n & 1][i], ans);
}
cout << "1\n" << ans;
return 0;
}
更多推荐
所有评论(0)