算法学习——差分

5 篇文章 0 订阅
文章提供了一段Java代码,展示了如何通过计算差分数组来高效处理棋盘上指定区域颜色取反的操作,通过差分数组的更新和计算,减少了计算复杂度。
摘要由CSDN通过智能技术生成

在了解差分之前,我们首先需要知道前缀和的概念。

前缀和简单介绍:

对于一个数组A,要求出A[0]~A[i]的和,我们通常的做法是遍历一边,加起来。但是要求m组这样的和,我们就要花费O(mn)的时间复杂度。显然不合理。所以我们要用到动态规划里的备忘录思想,创建一个新数组B,B[i]记录的是B[0]~B[i]的和。这个数组就是A的前缀和。

差分的概念:

有前缀和就有其逆定理。那就是假设数组A是一个前缀和数组,那么怎么求原数组呢B?答案是B[i] = A[i] - A[i-1] 这很好理解。这种算法可以被视为前缀和的逆运算

现在我们获得了差分的概念,让我们看看怎么使用它吧。

如何使用:

差分主要用处在于:

快速将序列A[l..r]的区间每个元素加上d。

正常加我们就需要不断遍历这一段数组。但是我们有了差分的概念,因此我们可以得到差分数组B[l]' = A[l] + d - A[l-1] = B[l] + d

B[r+1]' = A[r+1] -A[r] -d = B[r+1] - d

差分可以将在原序列上的 “区间操作” 转化为差分序列上的 “单点操作”

现在有了对一维数组的差分运算, 我们可以看看二维数组怎么操作。

二维差分:

二维差分要解决的问题是给原二维数组A的[x1,y1]~[x2,y2]处的所有元素加上d。

我们根据几何关系可以得出以下公式

Bi,j = Ai,j - Ai-1,j - Ai,j-1, + Ai-1,j-1

结合前面文章中差分的用途,可以容易的想到,二维差分主要是用于快速将一个区块中的所有元素加上 d

根据我们的公式我们很快得出一个结论:

对原数组A的[x1,y1]~[x2,y2]处的所有元素加上d等价于:

B[x1,y1] += d

B[x1,y2+1] -= d

B[x2+1,y1] -= d

B[x2+1,y2+1] += d

可以画一张图自己看看,推导很简单

应用:

问题描述

小兰拥有n*n 大小的棋盘,一开始棋盘上全是白子,小兰进行了m 次操作,每次操作会将棋盘上某个范围内的所有棋子的颜色取反(也就是白色棋子变为黑色,黑色棋子变为白色)。请输出所有操作做完后棋盘上每个棋子的颜色。

输入格式

输入的第一行包含两个整数 n,m,用一个空格分隔,表示棋盘大小与操作数。

接下来 m 行每行包含四个整数 x1,y1,x2,y2,相邻整数之间使用一个空格分隔,表示将在 x1~x1行,y1~y2 列中的棋子颜色取反。

输出格式

输出 n 行,每行 n 个 0 或  1 表示该位置棋子的颜色。如果是白色则输出 0,否则1

样例输入
3 3
1 1 2 2
2 2 3 3
1 1 3 3
样例输出
001
010
100

代码:

import java.util.Scanner;

public class Main extends Base{
  public static void main(String[] args) {
    int n = I(),m = I();
    int[][] sum = new int[n+1][n+1]; //原数组
    int[][] diff = new int[n+2][n+2]; //差分数组
    for(int k=0;k<m;k++){
      int x1 = I(),y1 = I(),x2 = I(),y2 = I();
      //每次对差分数组4个位置操作
      diff[x1][y1]++;
      diff[x1][y2+1]--;
      diff[x2+1][y1]--;
      diff[x2+1][y2+1]++;
    }
    //由差分数组得到原数组
    for(int i=1;i<=n;i++){
      for(int j=1;j<=n;j++){
        sum[i][j] = sum[i-1][j]+sum[i][j-1]+diff[i][j]-sum[i-1][j-1];
        if(sum[i][j]%2==0) print(0);
        else print(1);
      }
      print("\n");
    }
  }
}
class Base {
  static Scanner scan = new Scanner(System.in);
  static int I(){
    return scan.nextInt();
  }
  static <T> void println(T x){
    System.out.println(x);
  }
  static <T> void print(T x){
    System.out.print(x);
  }
}
sum[i][j] = sum[i-1][j]+sum[i][j-1]+diff[i][j]-sum[i-1][j-1];

这一行是 

Bi,j = Ai,j - Ai-1,j - Ai,j-1, + Ai-1,j-1

求Ai,j的运算变形

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值