在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; }