洛谷P2004--领地选择

133 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

领地选择

题目描述

作为在虚拟世界里统帅千军万马的领袖,小 Z 认为天时、地利、人和三者是缺一不可的,所以,谨慎地选择首都的位置对于小 Z 来说是非常重要的。

首都被认为是一个占地 C×CC\times C 的正方形。小 Z 希望你寻找到一个合适的位置,使得首都所占领的位置的土地价值和最高。

输入格式

第一行三个整数 N,M,CN,M,C,表示地图的宽和长以及首都的边长。

接下来 NN 行每行 MM 个整数,表示了地图上每个地块的价值。价值可能为负数。

输出格式

一行两个整数 X,YX,Y,表示首都左上角的坐标。

样例 #1

样例输入 #1

3 4 2
1 2 3 1
-1 9 0 2
2 0 1 1

样例输出 #1

1 2

提示

对于 60%60\% 的数据,N,M50N,M\le 50

对于 90%90\% 的数据,N,M300N,M\le 300

对于 100%100\% 的数据,1N,M1031\le N,M\le 10^31Cmin(N,M)1\le C\le \min(N,M)

开始我们可以想到一个很暴力的做法,就是枚举每个C×CC\times C的正方形,需要O(N3)O(N^3)的时间复杂度,显然会超时,因此我们想到二维前缀和。先将所有领地的价值的前缀矩阵和都表示出来,然后用两重循环遍历长度为CC的矩阵,找到之后,再遍历一下,寻找顶点位置,一旦找到就输出。

普及一下二维前缀和的模板:

for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		cin>>a[i][j];
	}
} 
for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
	}
}
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;

最后贴上代码:

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string> 
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack> 
#include <cmath>
#define ll long long
#define AC return
#define Please 0
using namespace std;
const int N=2020;
int fa[N]; 
typedef pair<int,int>PII;
int e[N],dist[N],idx=0,ne[N],h[N],v[N],n,m;
ll dp[N][N];
inline int read(){//快读 
	int x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=x*10+ch-'0'; 
		ch=getchar();
	}
	AC x*f;
}	
int a[N][N],s[N][N];
int main(){
	int n,m,c;//c为变长 
	n=read(),m=read();
	c=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=read();//读入数组
		}
	} 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
                        //初始化模板
		}
	}
	int maxn=-0x3f3f3f3f;//这里注意要价值可能是负数,所以初始值要变成最小
	for(int i=c;i<=n;i++){
		for(int j=c;j<=m;j++){
			maxn=max(maxn,s[i][j]-s[i][j-c]-s[i-c][j]+s[i-c][j-c]);
		}
	}
	for(int i=c;i<=n;i++){
		for(int j=c;j<=m;j++){
			if(s[i][j]-s[i][j-c]-s[i-c][j]+s[i-c][j-c]==maxn){
				cout<<i-c+1<<" "<<j-c+1;
				break;
			}
		}
	}
	AC Please;
}

希望能帮到大家(QAQQAQ