题目:激光炸弹 考察内容:二维前缀和 题目链接:99. 激光炸弹 - AcWing题库
思路:
上面推导的公式从左上(1,1)一直到右下(i,j)推导出的结论,
" src="https://uploadfiles.nowcoder.com/images/20220815/318889480_1660553763718/D9FDAE9918A39C99254A9D8D179628E5" />若放入一个坐标中需要沿x轴投影,即从左下的(1,1)遍历到右上的(i,j),而递推式中A[i][j] 为该坐标系中右上的点:即代码从(r,r)开始遍历直到遍历完所有坐标系中所有的点
#include <bits/stdc++.h> #define ios \ ios::sync_with_stdio(false); \ cin.tie(nullptr); \ cout.tie(nullptr) #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,a,n) for(int i=n;i>=a;i--) #define lowbit(x) ((x) & - (x)) #define pb push_back #define SZ(v) ((int)v.size()) #define PI acos(-1) #define x first #define y second #define mem(a,b) memset((a),(b),sizeof(a)) using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const ll LLINF=0x3f3f3f3f3f3f3f3fLL; const double eps=1e-6; const int MAX=2e5+10; const ll mod=1e9+7; /********************************* std-head *********************************/ using namespace std; const int N = 5e3 + 10; //不能开 1e5+10, 内存限制比较严格 int s[N][N]; int n, r; int main() { ios; cin >> n >> r; r = min(5001, r); // 因为r最大可以取 10^9 for (int i = 0; i < n; i++) { int x, y, w; cin >> x >> y >> w; // s[++x][++y]=w; //错误 s[++x][++y] += w; //右移一位, 就不需要考虑边界了, 并且必须是+=, 不能是=, 因为1个位置可能有多个目标 } for (int i = 1; i <= 5001; i++) { for (int j = 1; j <= 5001; j++) { // s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j](a[i][j]); s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; //求出坐标系中每个点相对于(1,1)的二维前缀和 } } int ans = 0; for (int i = r; i <= 5001; i++) { for (int j = r; j <= 5001; j++) { ans = max(ans, s[i][j] - s[i - r][j] - s[i][j - r] + s[i - r][j - r]);//获得点(i,j)在正方形边长为R的区域的前缀和 } } cout << ans << endl; return 0; }