日常刷题2025-3-7

日常刷题2025-3-7

收集金币

https://ac.nowcoder.com/acm/contest/102742/D考点:dp

正解:路径DP

如果没有变成墙壁的条件,就是很经典的一道入门DP,公式 \(dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) + val[i][j]\)。 由于只能向右和下移动,记左上角坐标 \((1,1)\),那么到达点 \((i, j)\) 的回合一定是 \(i - 1 + j - 1\)。如果变成墙壁是在这个回合及之后,那么就可以直接通过,反之点权赋极小值即可。

评述

想到了DP,不过卡在了时间复杂度上,甚至还想了一个bfs的算法,可惜被卡。有时候需要相信自己的直觉,DP做不出来有可能是因为题目还没有理解透彻。

代码

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;

void solve(){
	int n, m;
	std::cin >> n >> m;

	std::vector tag(n+1, std::vector<int>(m+1, 1e9));
	std::vector d(n+1, std::vector<int>(m+1));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			std::cin >> d[i][j];

	int t; std::cin >> t;
	for (int i = 0; i < t; i++)	{
		int x, y, v; std::cin >> x >> y >> v;
		tag[x][y] = v;
	}

	std::vector dp(n+1, std::vector<i64>(m+1, -1e9));
	dp[1][1] = d[1][1];
	// dp[0][1] = 0;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			if (i + j - 2 >= tag[i][j]) d[i][j] = -1e9;
		}
	}

	i64 ans = d[1][1];
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			if (i == 1 && j == 1) continue;
			dp[i][j] = std::max(dp[i-1][j], dp[i][j-1])+d[i][j];
			ans = std::max(ans, dp[i][j]);
		}
	}

	std::cout << ans << '\n';

}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}
posted @ 2025-03-07 22:05  califeee  阅读(16)  评论(0)    收藏  举报