题解 P2004 【领地选择】
GossWandering · · 题解
题意大概是说
根据题意,我们可以枚举左上角的坐标,利用边长
时间复杂度:
O(nmc^2) 预计得分:50~70 points
程序如下:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1010;
int n,m,c;
int val[N][N],maxx=-inf,wherex,wherey;
int main(){
scanf("%d%d%d",&n,&m,&c);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&val[i][j]); //输入
for(int x1=1; x1<=n-c+1; x1++)
for(int y1=1; y1<=m-c+1; y1++){ //枚举左上角
int x2=x1+c-1;
int y2=y1+c-1; //计算右下角
int ans=0;
for(int i=x1; i<=x2; i++)
for(int j=y1; j<=y2; j++)
ans += val[i][j];
if(ans>maxx){
maxx=ans;
wherex=x1;
wherey=y1;
}//更新答案
}
printf("%d %d",wherex,wherey);
return 0;
}
提交上去??啊,果然70分。沮丧的我们不得不思考优化。
在此之前,我们思考,我们写出的程序到底差在哪儿???
请先思考,再往下阅读
原来,我们的程序有些地方算重复了:
其中
怎么来的呢?我们画一下图就知道了。
一开始是这样的:
回顾转移方程:
第一个加的是
此后再加上
既然重复计算了,那我们就剪掉,即减去
即加上:
所以我们用图解证明了转移方程
我们看一下实现代码:
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
f[i][j]=val[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
现在只需枚举左上角,根据边长
附
这可以用二维前缀和的定义进行理解,或用图解也行。
完整代码不提供了,其余几篇题解都讲的挺好。