C++
$\color{gold}{— > 蓝桥杯辅导课题解}$
70分:
思路:
二维前缀和
$通过二维前缀和处理一下每个子矩阵,然后4重循环枚举每个子矩阵,符合则res++$
$时间复杂度:O(n^4)$
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
typedef long long ll;
int n, m, k;
int s[N][N];
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
cin >> s[i][j];
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
ll res = 0;
for (int x1 = 1; x1 <= n; x1 ++)
for (int y1 = 1; y1 <= m; y1 ++)
for (int x2 = x1; x2 <= n; x2 ++)
for (int y2 = y1; y2 <= m; y2 ++) {
if (s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] <= k)
res ++;
}
cout << res;
return 0;
}
100(满分)
思路:
一维前缀和 双指针
$1、将列看成一个整体$
$2、i, j 枚举列的上下边界,通过双指针l, r维护列的左右边界$
$3、sum存储枚举列的和,如果大于sum>k了,列的左边界l++,直到sum<=k$
$4、res记录一下从l到r这一段列的贡献:r-l+1$
$时间复杂度:O(n^3)$
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
typedef long long ll;
int n, m, k;
int s[N][N];
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++) {
cin >> s[i][j];
s[i][j] += s[i - 1][j]; // 每列上的一维前缀和
}
ll res = 0;
for (int i = 1; i <= n; i ++) // i j 上下边界
for (int j = i; j <= n; j ++)
for (int l = 1, r = 1, sum = 0; r <= m; r ++) { // l r 左右边界
sum += s[j][r] - s[i - 1][r];
while (sum > k) {
sum -= s[j][l] - s[i - 1][l];
l ++;
}
res += r - l + 1;
}
cout << res;
return 0;
}
res+=r-l+1;
//r是不断循环变化的,每更新一次r又经while循环后符合条件的带r列的矩形,就是r-l+1个
//0 1 2,带二的一维矩形分别是 012,12,2
终于懂啦,感谢佬!!
一样的思路,只不过你是累和记录区间的值,我是直接利用二位前缀和得出,不用每次加加减减总和,而是可以一步求出,但是我不知道为什么过不了样例,求指点
看代码:
多谢兄弟,昨天把if判断删了然后过了我就反应过来了,害真不知道说什么好,感觉不应该出这种问题,又感觉出了这种问题活该。。
为什么从l到r贡献了(r-l+1)个?
看我Python来也
orzzzzzz
tpllllllllllll
sum += s[j][r] - s[i - 1][r];这里看不懂
大佬们,时间复杂度怎么算啊,三重for,r,l,最坏不是二者都到m吗?还是o(n^4)?不会算😓
想了挺久,终于想到了
请问这条while里面的这条语句为什么这么写
sum -= s[j][l] - s[i - 1][l];
因为sum大了,要减小,所以 l 要+ +,s[j][l]-s[i-1][l]就是求i-j中 第l 列的总和
感谢大佬,讲的好好!学会了