一维&二维前缀和

基础知识:

  一维前缀和:

      S[ i ] = a[ 1 ] + a[ 2 ] + ... a[ i ]
      a[ l ] + ... + a[ r ] = S[ r ] - S[l - 1]

  二维前缀和:

      S[i, j] = 第 i 行 j 列格子左上部分所有元素的和

      以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:

        S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

 

1. 激光炸弹

  题目链接:https://www.acwing.com/problem/content/101/ (算法竞赛进阶指南)

  思路:1. 先求出每一个以(i, j)为右下角节点,(0, 0) 为左上角节点的矩形的二维前缀和

        2. 枚举每一个R * R的矩阵,求出最大值

  代码:

 

#include <algorithm>
#include <cstring>
#include <iostream>

using namespace std;

#define N (int)5e3 + 10

int n, m;
int s[N][N];

int main(void)
{
    int cnt, R;
    scanf("%d%d", &cnt, &R);
    R = min(R, 5001);
    n = m = R; 
    //扩展到和R一样大
    
    while(cnt--)
    {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        n=max(n,++x),m=max(m,++y);
        s[x][y] += w; 
        //不同目标可能在同一位置
    }
    
    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];
    int res = 0;
    
    // 枚举所有边长是R的矩形, 枚举(i,j) 为右下角
    for(int i = R; i <= n; i++)
        for(int j = R; j <= m; j++) 
            res = max(res, s[i][j] - s[i - R][j] - s[i][j - R] + s[i - R][j - R]);
            
    printf("%d\n", res);
    return 0;
}

 

posted @ 2020-08-10 02:57  锤子科技未来产品经理  阅读(106)  评论(0)    收藏  举报