二维前缀和:
求和的公式:s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]
s数组是前缀和数组,a数组保存(i,j)点的值,并且s数组保存的是从(1,1)到(i,j)的矩阵的和
贴个代码:
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
long long x;
cin >> x;
mp[i][j] = mp[i - 1][j] + mp[i][j - 1] - mp[i - 1][j - 1] + x;
}
}
前缀和保存的是从(1,1)点开始计算的前缀和,如果想要从其他点开始计算前缀和的话,可以利用差分的操作。
贴个公式:ans=mp[x2][y2]-mp[x2][y1-1]-mp[x1-1][y2]+mp[x1-1][y1-1];
(x1,y1)是起点位置 (x2,y2)是终点位置
贴个暴力前缀和的做法(80分)O()
#include <iostream>
using namespace std;
int n, m, k;
long long mp[510][510];
int main()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
long long x;
cin >> x;
mp[i][j] = mp[i - 1][j] + mp[i][j - 1] - mp[i - 1][j - 1] + x;
}
}
int cnt = 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++)
{
long long ans=mp[x2][y2]-mp[x2][y1-1]-mp[x1-1][y2]+mp[x1-1][y1-1];
if (ans <= k)
cnt++;
}
}
}
}
cout << cnt << endl;
return 0;
}
剩下的两个点会超时......
随便贴个正解(双指针)
#include <iostream>
using namespace std;
const int N=510;
int a[N][N];
int main ()
{
int n,m,k;
cin >> n>> m>>k;
for (int i=1;i<=n;i++)
for (int j = 1; j <= m ; j++)
cin >> a[i][j],a[i][j] += a[i-1][j];
long long res = 0;
for (int i=1;i<=n;i++)
{
for (int j=i;j<=n;j++)
{
for (int l = 1 , r = 1 , sum = 0 ; r <= m ; r++ )
{
sum += a[j][r]-a[i-1][r];
while (sum > k)
{
sum -= a[j][l]-a[i-1][l];
l++;
}
res += r-l+1;
}
}
}
cout << res<< endl;
return 0;
}