洛谷 P2280 [HNOI2003]激光炸弹
题目:
题解:
- 二维前缀和。
- 诈一看似乎是线段树/暴力?
- 首先第一个难点是题目说目标位于爆破正方形边上的不算。这个问题怎么解决。其实就可以把每个目标的坐标向右上角平移一位。
- 举个例子,(0, 0)和(1, 1),原本sum(1, 1)是2的(不符合题意);平移之后变成了(1, 1)和(2, 2),sum(1, 1)变成了1,符合题意。
- 第二个难点是题目说炸弹为正方形,所以以(i, j)为右上角的答案就不是简单的sum(i, j) = sum(i - 1, j) + sum(i, j - 1) - sum(i - 1, j - 1)了。而是在更新完sum后,每次ans取max,如下↓
- ans = max(ans, sum(i, j) - sum(i - r, j) - sum(i, j - r)+ sum(i - r, j - r))
- 这样就能保证取到的ans是以(i, j)为右上角的正方形(强烈建议画图理解)
#include <iostream>
#include <cstdio>
#define maxn 5005
using namespace std;
int n, r, ans;
int sum[maxn][maxn];
int main()
{
cin >> n >> r;
for(int i = 1; i <= n; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
sum[x + 1][y + 1] = z;
}
for(int i = 1; i <= 5000; i++)
for(int j = 1; j <= 5000; j++)
sum[i][j] += (sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]);
for(int i = r; i <= 5000; i++)
for(int j = r; j <= 5000; j++)
ans = max(ans, sum[i][j] - sum[i - r][j] - sum[i][j - r] + sum[i - r][j - r]);
cout << ans;
return 0;
}