java | 二维前缀和与差分

模版

注意,对区间更新用的是差分数组,而求任何一个区间的和用的是前缀和数组。

  • 原数组转差分数组

diff[i][j] = diff[i][j] - diff[i - 1][j] + diff[i][j - 1] + diff[i - 1][j - 1]
  • 把差分数组还原为原数组

diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1]
  • 用前缀和数组求(x_1,y_1)(x_2,y_2)的所有元素和

ans = sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1  -1][y1 - 1]
  • 用差分数组将(x_1,y_1)(x_2,y_2)的所有元素加target

    public static void add(int x1, int y1, int x2, int y2, int target) {
        diff[x1][y1] += target;
        diff[x1][y2 + 1] -= target;
        diff[x2 + 1][y1] -= target;
        diff[x2 + 1][y2 + 1] += target;
    }

P3397 

 这道题要对二维区间进行维护,于是使用差分数组,最后再复原为原数组。

import java.io.*;

public class P3397 {
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    public static StreamTokenizer t = new StreamTokenizer(br);
    public static PrintWriter out = new PrintWriter(bw);
    public static int nextInt() throws Exception {
        t.nextToken();
        return (int) t.nval;
    }
    public static int n, m;
    public static int[][] carpet;
    public static void add(int x1, int y1, int x2, int y2, int target) {
        carpet[x1][y1] += target;
        carpet[x1][y2 + 1] -= target;
        carpet[x2 + 1][y1] -= target;
        carpet[x2 + 1][y2 + 1] += target;
    }
    public static void back() {
        for (int i = 1; i <= n; i += 1) {
            for (int j = 1; j <= n; j += 1) {
                carpet[i][j] += carpet[i - 1][j] + carpet[i][j - 1] - carpet[i - 1][j - 1];
                out.print(carpet[i][j] + " ");
            }
            out.println();
            out.flush();
        }
    }
    public static void main(String[] args) throws Exception {
        n = nextInt();
        m = nextInt();
        carpet = new int[n + 2][n + 2];
        for (int i = 1; i <= m; i += 1) {
                add(nextInt(), nextInt(), nextInt(), nextInt(), 1);
        }
        back();
    }
}

P1719 

构造二位前缀和, 计算任何一个矩阵的和。

import java.util.Scanner;

public class P1719 {
    public static int n, max;
    public static int[][] matrix;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        matrix = new int[n + 1][n + 1];
        for (int i = 1; i <= n; i += 1) {
            for (int j = 1; j <= n; j += 1) {
                matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1] - matrix[i - 1][j - 1] + in.nextInt();
            }
        }
        for (int x1 = 1; x1 <= n; x1 += 1) {
            for (int y1 = 1; y1 <= n; y1 += 1) {
                for (int x2 = x1; x2 <= n; x2 += 1) {
                    for (int y2 = y1; y2 <= n; y2 += 1) {
                        int sum = matrix[x2][y2] - matrix[x2][y1 - 1] - matrix[x1 - 1][y2] + matrix[x1 - 1][y1 - 1];
                        max = Math.max(max, sum);
                    }
                }
            }
        }
        System.out.print(max);


    }
}

P1387

 

 正方形也就是一个矩阵内的和等于边长的平方,要求任何一个区间的和,用前缀和数组。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;

public class P1387 {
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static StreamTokenizer t = new StreamTokenizer(br);
    public static int nextInt() throws Exception {
        t.nextToken();
        return (int) t.nval;
    }
    public static int n, m;
    public static void main(String[] args) throws Exception{
        n = nextInt();    m = nextInt();
        int ans = 0;
        int[][] grid = new int[n + 1][m + 1];
        Arrays.fill(grid[0], 0);
        for (int i = 1; i <= n; i += 1) {
            grid[i][0] = 0;
        }
        for (int i = 1; i <= n; i += 1) {
            for (int j = 1; j <= m; j += 1) {
                grid[i][j] += grid[i - 1][j] + grid[i][j - 1] - grid[i - 1][j - 1] + nextInt();
            }
        }
        for(int i = 1; i <= n; i += 1) {
            for (int j = 1; j <= m; j += 1) {
                for (int a = 1; a <= Math.min(n - i + 1, m - j + 1); a += 1 ) {
                    int x = i + a - 1, y = j + a - 1;
                    if (grid[x][y] - grid[x][j - 1] - grid[i - 1][y] + grid[i - 1][j - 1] == a * a) {
                        ans = Math.max(ans, a);
                    }
                }
            }
        }
        System.out.print(ans);
    }
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值