洛谷 P2280 激光炸弹
题目链接:激光炸弹
思路
看到消灭一个正方形内的所有目标就会想到二维前缀和。输入的x, y可能相同,所以同一个位置可能会有多个目标所以在初始化的时候需要使用dp[x + 1][y + 1] += v;
,而不是dp[x + 1][y + 1] = v
。为了使得二维前缀和计算的时候不会数组越界,所以将地图范围改为[1, 5001],使得在使用公式dp[i][j] += dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1]
的时候不用分类讨论。
二维前缀和:只能摧毁边长为m的正方形内的所有目标,所以需要依靠二维前缀和来求出一个长方形内的所有目标的总价值,如dp[i][j] - dp[i - m][j] - dp[i][j - m] + dp[i - m][j - m]
,然后枚举每个变长为m的正方形的右下角顶点的位置,并不断更新最大总价值res。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10;
#define ll long long
ll n, m;
ll dp[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
ll x, y, v;
cin >> x >> y >> v;
dp[x + 1][y + 1] += v;
}
for (int i = 1; i <= 5e3 + 5; i++) {
for (int j = 1; j <= 5e3 + 5; j++) {
dp[i][j] += dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1];
}
}
ll res = 0;
for (int i = m; i <= 5e3 + 5; i++) {
for (int j = m; j <= 5e3 + 5; j++) {
res = max(res, dp[i][j] - dp[i - m][j] - dp[i][j - m] + dp[i - m][j - m]);
}
}
cout << res << endl;
return 0;
}