## 1、激光炸弹 #### 录入训练 https://www.acwing.com/problem/content/101/ #### 温故知新 - 点坐标如何修改为数组方格坐标 - 二维前缀和 - 不能开两个数组,因为每个数组是$5000x5000$这么大,就是$5000x5000x4bytes,5000x5000x4/1024/1024=95MB$,这题的空间是$168MB$,所以两个数组会$MLE$。 一个数组就行了,在自己身上求前缀和。 - $xy$坐标是从$0$开始的,二维前缀和需要坐标从$(1,1)$开始,需要$x++,y++$ - 炸弹的范围会超过$r>M$,会导致计算二维前缀和的两层循环失效,造成结果错误。正确的作法是时刻小心观察,循环什么情况下不会执行,然后加上特判。 - 只枚举右下角即可完成所有边长为$r$的正方形枚举 ### 蓝桥杯第13届省赛中级组第6题 ![](http://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/2023/02/b15ecc654c62371bfd8433381b1a3110.png) ![](http://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/2023/02/7d8e8d0f52943660628d42fa572d70ea.png) ```cpp {.line-numbers} #include /* 测试用例I: 5 6 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 答案 4 测试用例II: 5 6 1 0 1 0 0 0 0 1 0 1 1 0 1 0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 答案 2 */ using namespace std; const int INF = 0x3f3f3f3f; const int N = 110; int a[N][N]; int s[N][N]; int res; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { cin >> a[i][j]; s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; } for (int i = 1; i <= n; i++) // 100 for (int j = 1; j <= m; j++) { // 100 for (int k = 0;; k++) { if (i + k > n || j + k > m) break; // 越界 if (a[i + k][j + k] == 0) break; int x1 = i, y1 = j, x2 = i + k, y2 = j + k; int cnt = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]; if (cnt != k + 1) break; res = max(res, cnt); } } printf("%d\n", res); return 0; } ```