霰弹枪[二维的前缀和]

 在clyz有一个很厉害的枪手叫做东哥,他的女神qy被本地一个著名的黑帮老大XXX给绑架了,东哥急切地想要找回qy,向椅子买了几件武器。因为首先要轰开clyz的大门,所以他选择了霰弹枪。clyz的大门由N*M块石头组成,而东哥的体积为R行C列(东哥不可被切开),他为了省子弹,他只能轰出一个恰好自己通过的洞,每块石头的价值不同,打碎可获得的金钱也不同,东哥要攒钱买武器,所以要选择轰最大价值的一部分石头,现在他想要知道自己能够获得多少金钱购买下一把武器。

输入格式

第1行:4个正整数N,M,R,C

第2..N+1行:每行M个正整数,第i+1行第j个数表示num[i][j]

输出格式

1行:1个整数,表示东哥最多能获得的金钱

输入样例

3 5 2 3

5 2 7 1 1

5 9 5 1 5

3 5 1 5 3

输出样例

33

数据范围

对于60%的数据:1 <= N,M <= 200

对于100%的数据:1 <= N,M <= 1,000

1 <= R <= N, 1 <= C <= M

1 <= num[i][j] <= 1000

保证结果不超过2,000,000,000

题解:

这题有点像求最大子矩阵,但是因为范围是固定的,所以用二维的前缀和搞搞,然后暴力扫一遍即可

之前只会简单一维的前缀和,第一次打二维的,算是学习了一下吧

首先先说一下原理好了

f[i][j]表示从1,1到i,j这个矩形的总和

怎么求这个总和呢?

f[i][j] = f[i-1][j] + f[i][j-1] + x - f[i-1][j-1]

根据斥容原理可知,f[i-1][j-1]算了两次..

怎么表示所求矩形的总和呢?

不懂怎么说,随便附上个图好了:

就比如,我们现在要求图中两个黑点所形成的矩阵的和,

这个和等于 大的矩阵-两个红的矩阵+小的矩阵(同样是斥容原理)

然后注意一下矩阵和的边界即可:

附上代码:

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int n,m,r,c,x;
int sum[1001][1001];
int ans;
int main(){
	freopen("data.txt","r",stdin);
	scanf("%d%d%d%d",&n,&m,&r,&c);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++){
	    	scanf("%d",&x);
	    	sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
	    }
	for(int i=1;i<=n-r+1;i++)
	    for(int j=1;j<=m-c+1;j++){
	        int temp=sum[i+r][j+c]-sum[i][j+c]-sum[i+r][j]+sum[i][j];
	        ans=max(ans,temp);
	    }
	cout<<ans;
	return 0;
}

  

原文地址:https://www.cnblogs.com/polebug/p/4070303.html