99.激光炸弹

原题链接:Acwing99. 激光炸弹


解题思路

因为Xi,Yi的值在0~5000之间,所以我们可以建立一个二维数组 A,其中 A[i,j] 就等于位置 (i,j) 上的所有目标的价值之和。即对于每个目标,令 A[Xi,Yi]+=Wi
接下来我们求出 A 的二维前缀和 S,即:

S[i,j] = ∑(i,x=1)∑(j,y=1)A[z,y]

如下图所示,我们再观察 S[i,j],S[i-1,j],S[i,j-1],S[i-1,j-1] 的关系。

容易得到如下递推式:

S[i,j] = S[i-1,j] + S[i,j-1] - S[i-1,j-1] + A[i,j]

同理,对于任意一个边长为 R 的正方形,我们有:

∑(i,x=i-R+1)∑(j,y=j-R+1) A[x,y] = S[i,j] - S[i-R,j] - S[i,j-R] + S[i-R,j-R]

因此我们只需要 O(N2) 递推求出二维前缀和 S,然后 O(N2) 枚举边长位 R 的正方形的右下角坐标 (i,j),即可通过上式 O(1) 计算出该正方形内所有目标的价值之和,更新答案。

样例代码

#include<iostream>
#include<cstdio>
using namespace std;
int f[5010][5010],n,m,r,c,x,y,z,i,j,ans;
int main()
{
    cin>>n>>m;
    r=c=m;
    for(i=1; i<=n; i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        x++,y++;
        f[x][y]+=z;
        r=max(r,x);
        c=max(c,y);
    }
    for(i=1; i<=r; i++)
        for(j=1; j<=c; j++)
            f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+f[i][j];
    for(i=m; i<=r; i++)
        for(j=m; j<=c; j++)
            ans=max(ans,f[i][j]-f[i][j-m]-f[i-m][j]+f[i-m][j-m]);
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/hnkjdx-ssf/p/14163572.html