洛谷P2213题解
题目思路
本人使用了 \(O{(n^3)}\) 算法,不喜勿喷。
因为变量 \(k\) 已知,所以说关于一个点的所有可以到的点便在一个一这个点为中心的菱形中,当然,这个菱形可能会不全在正方形内,此时,我们便要求的就是菱形与正方形相交部分的数总和。
那应该怎么求相交部分呢?利用前缀和,不过这一次的前缀和有所特殊,并非标准二维前缀和,而是为该行的前缀和,类似多个一维前缀和,也就是说对于一个点的前缀和 \(sum_{i,j}=sum_{i,j-1}+num_{i,j}\)。
总共有 \(n^2\) 个点,由于利用前缀和优化使得求菱形与正方形相交部分的数总和的次数为 \(n\) 次,所以说,复杂度为 \(O{(n^3)}\)。
剩下的就是代码部分(注释均在代码内)。
CODE
#include<stdio.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int map[405][405];
int dp[405][405];//前缀和数组
int n,k;
long long ans=-1;//答案初始化
void point(int x,int y,int k,int n){
long long num=0;
for(int i=max(1,x-k);i<=min(n,x+k);i++){//注意边界
int kp=k-abs(x-i);
//我们注意到,在x轴方向和y轴方向移动距离之和为k,符合菱形特性
num+=dp[i][min(n,y+kp)]-dp[i][max(0,y-kp-1)];//注意边界
}
ans=max(num,ans);
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&map[i][j]);
dp[i][j]=dp[i][j-1]+map[i][j];//单行前缀和计算
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
point(i,j,k,n);//枚举每一个点
}
}
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号