题目描述

输入n个坐标(x,y)与其对应的分数(v),求边长为r的正方形区域内最大的分数和

数据范围:1<=n<=10^4, 0<=x,y<=5000, 0<=r<=5000, 1<=v<=1000

分析

使用二维前缀和的方法,对于所求的边长为r的正方形的和为f[x][y] - f[x-r][y] - f[x][y-r] + f[x-r][y-r]

ac代码

具体细节见注释

ps:关于前缀和几种计算方式以及对于高维时的优劣,包括拓展到二维差分,可以查看该篇文章,我看完受益匪浅(膜拜大佬orz)

#include<bits/stdc++.h>
using namespace std;
#define MAX 5001//因为坐标从0开始,所以为了方便计算,所有坐标加1
int main()
{
    int r = 0, n = 0, x = 0, y = 0, v = 0;
    int f[MAX+1][MAX+1] = { 0 };//数组开大放越界
    memset(f, 0, sizeof(f));
    scanf("%d %d", &n, &r);
    for (int i = 0; i < n; i++)
    {
        scanf("%d %d %d", &x, &y, &v);
        f[x+1][y+1] +=v;//不知道为什么,在洛谷中直接使用'='赋值会有一个测试点无法通过,二编:破案了,洛谷题目写了可能同一点会有多个不同的目标,所以需要加等
    }
    int ans = 0, sum = 0;
  //第一种求二维前缀和的方法
    /*
    for (int i = 1; i <= MAX; i++)
    {
        for (int j = 1; j <= MAX; j++)
        {
            f[i][j] = f[i][j] + f[i - 1][j] +f[i][j - 1] -  f[i - 1][j - 1];
        }
    }
    */
  //第二种求二维前缀和的方法
    for (int i = 1; i <= MAX; i ++)
		for (int j = 1; j <= MAX; j ++) f[i][j] += f[i][j - 1];
	for (int j = 1; j <= MAX; j ++)
		for (int i = 1; i <= MAX; i ++) f[i][j] += f[i - 1][j];
  
  
  //求出最大值
    for(int i = r;i <= MAX;i++)
    {
        for(int j = r;j <= MAX ; j++)
        {
            sum = f[i][j] - f[i - r][j] - f[i][j - r] + f[i - r][j - r];
            ans = max(ans , sum);
        }
    }
    printf("%d", ans);
    return 0;
}

总结

这题实际上学会了二维前缀和还是挺简单的,但是我中间调整数据,以及理解题目花了不少时间。