前缀和与差分

前缀和与差分

一维前缀和:
定义:

​ 前缀和是指某序列的前n项和

公式:
输入:
	s[i] = arr[0]  		i = 0

​	s[i]=s[i−1]+arr[i]     i > 0 
输出:
[left - right];

s[right] - s [left - 1];
应用场景:

可以快速的查询某一个区间的和

Code

#include <stdio.h>
int main()
{
    int total;
    int left , right ; //求left - right 范围的和
    scanf("%d",&total);
    int arr[total] = {0};
    int sum[total] = {0};
    for( int i = 0 ; i < total ; i++ ) //数据写入数组,原数组arr
    {	
        scanf("%d",&arr[i]);
    }	

    //求前缀和
    for( int i = 0 ; i < total ; i++ )
    {
        if( i == 0 )
        {
            sum[i] = arr[i]; // 0下标等于0 
        }
        else
        {
            sum[i] = sum[i-1] + arr[i]; //前缀和
        }
    }	
    scanf("%d%d",&left,&right);
    // [left right]的和
    printf("%d" , sum[right] - sum[left - 1] );
	
    return 0;
}
二维前缀和
定义:

矩阵的和

公式:
求sum:
	 s [ i ] [ j ] = s [ i ] [ j − 1 ] + s [ i − 1 ] [ j ] − s [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] 
输出:
 sum[x2 ] [y2] - sum[ x2 ] [y1-1] - sum[ x1-1 ] [ y2] + sum[x1-1] [y1-1] 
应用场景:

对于二维矩阵可以快速的求解某一个矩阵的面积

img

code

#include <Stdio.h>
int n = 3 , m = 4;
int arr[n][m] = { {1 , 5 , 6 , 8 }
				  {9 , 6  , 7 , 3 }
				  {5 , 3  , 2 ,  4}
								};
int sum[m][n];

void pre_sum()
{
//初始化开始	
	sum[0][0] = arr[0][0]; 	//0特殊位置 初始化
	//竖着的初始化
	for(int i = 1 ; i < n ; i++ )
	{
		sum[i][0] = sum[i-1][0] + arr[i][0];
	}
	//横着的初始化
	for(int j = 1 ; j < m ; j++ )
	{
		sum[0][j] = sum[0][j-1] + arr[0][j];
	}
	for(int i = 1 ; i < n ; i++ )
	{
		for(int j = 1 ; j < m ; j++ )
		{
			sum[i][j] = sum[i-1][j] + sum[i][j-1] + arr[i][j] - sum[i-1][j-1];
		}
	}
//初始化结束
}
int getsum(int x1 ,int y1, int x2 ,int y2)
{
	//情况1: x1,y1在(0,0),矩阵很舒服,直接返回就ok 
	if( x1 == 0 && x2 == 0 )
	{
		return sum[x2][y2];	
	}
	//情况2:x1 为 0 ,左上角行为0 抽象为多行的一维前缀和
    if( x1 == 0 )
    {
		return sum[x2][y2] - sum[x2][y1-1];
	}
	//情况3:y1 为 0 ,左上角列为0 ,抽象为多列的一维前缀和
	if( y1 == 0 )
	{
		return sum[x2][y2] - sum[x1-1][y2];
	}
	
	return sum[x2][y2] - sum[x2][y1-1] - sum[x1-1][y2] + sum[x1-1][y1-1];
	

}

int main()
{
	
	//int n , m; //数组规模
	//scanf("%d%d",&n,&m);
	//初始化的操作和二维动态规划很像!	
	int x1 ,y1,x2,y2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	pre_sum();
	int ans = getsum(x1,y2,x2,y2);
	printf("%d",ans);
	return 0;
}
差分
定义:

​ 差分就是将数列中的每一项分别与前一项做差

​ 一般认为:差分是前缀和的逆运算

​ 差分序列第一个数原来的第一个数一样

​ 开数组的时候,要比原来的 arr 数组多开一个大小

性质

​ 差分序列求前缀和可得原序列

公式
求差分数组:

​ 只需要对范围[left , right ]

d[left] += val;
d[right + 1 ] -= val; 

​ 使差分数组在left, right范围内实现+ val ;

差分求前缀和:
a[i]=a[i]+a[i−1]

差分求前缀和为原数组

应用场景

当求序列的某个区间 + / - val 时

Code
#include <Stdio.h>

void add(int left ,int right , int val)
{
	d[left] += val;
	d[right + 1] -= val; 
}
int main()
{
	int total , line;
	scanf("%d%d",&total,&line);
	for(int i = 0 ; i < total ; i++ )
	{
		scanf("%d",&arr[i]);	
	}
	int left , right,val;
	//假设1次
	scanf("%d%d%d",&left,&right,&val);
	add(left,right,val);
	
	//差分求前缀和
	for(int i = 0 ; i < total; i++ )
	{
		d[i] += d[i-1];
	}
	
	//原序列和差分合并完成 + / - val
	for(int i = 0 ; i < total ; i++ )
	{
		arr[i] += d[i]; 
		printf("%d",arr[i]);
	}
	return 0;
}

对于下面这行

arr[i] += d[i]; 

因为我们差分数组开的时全是0 , 而不是原数组复制一遍

所以,我们最后要写回去!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值