解题思路

作为一名蒟蒻,默默地展开了算法标签,发现是 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)

  1. ( i , j − x i ) (i, j - x_i) (i,jxi) 走到 ( i , j ) (i, j) (i,j),即小鸟飞到 ( i , j − x i ) (i, j - x_i) (i,jxi) 时,玩家点击了屏幕一次,然后小鸟就飞到了 ( i , j − x i ) (i, j - x_i) (i,jxi)。(玩家连续点击的情况)
  2. ( i − 1 , j − x i ) (i - 1, j - x_i) (i1,jxi) 走到 ( i , j ) (i, j) (i,j),即小鸟飞到 ( i − 1 , j − x i ) (i - 1, j - x_i) (i1,jxi) 时,玩家点击了屏幕一次,然后小鸟就向右飞了一个单位长度,又向上飞了 x i x_i xi 个单位长度,最后到达了 ( i − 1 + 1 , j − x i + x i ) (i - 1 + 1, j - x_i + x_i) (i1+1,jxi+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;
}
Logo

集算法之大成!助力oier实现梦想!

更多推荐