基础算法(三)

前缀和与差分

前缀和

即数组前n项和
s n = a 1 + a 2 + . . . . . . . . + a n − 1 + a n sn=a_1+a_2+........+a_{n -1}+a_n sn=a1+a2+........+an1+an
定义 s 0 = 0 s_0=0 s0=0
类似于级数的一种应用

计算公式为s[r]-s[l-1]
在这里插入图片描述

#include <iostream>
using namespace std;

const int N=1e5+10;

int q[N],s[N];

int n,m;

int main(){
    scanf("%d%d",&n,&m);
    
    for(int i=1;i<=n;i++)scanf("%d",&q[i]);
    
    for(int i=1;i<=n;i++)s[i]=s[i-1]+q[i];     //将前项数组和定义到另外一个数组中
    
    while(m--){
        int l,r;
        
        scanf("%d%d",&l,&r);
        
        int sum=s[r]-s[l-1];
        
        printf("%d\n",sum);
        
    }
    
 return 0;
}
//或者直接写

for(int =1;i<=n;i++){
    
    cin>>s[i];
    
    s[i]+=s[i-1];
}

矩阵前缀和(二维)

在这里插入图片描述

讲一下思路
和小学的算面积题差不多
首先x1y1,x2y2分别是所给矩阵中任意选取的一个小矩阵
分别是其左上角和右上角的坐标
要求是算出这个小矩阵中数的和

  • 先求前缀和,二维的前缀和计算的是从0开始的每一个矩阵的元素和

在这里插入图片描述

#include <iostream>
using namespace std;
int n,m,q;
const int N=1010;
int a[N][N],s[N][N];
int  main(){
scanf("%d%d%d",&n,&m,&q);

for(int i=1;i<=n;i++)//s[0][0]应当等于0,所以应从下标11开始存数
   for(int j=1;j<=m;j++)
   scanf("%d",&a[i][j]);
   
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]+a[i][j];//前缀和求和公式
while(q--){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int sum=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];根据面积图计算小矩形面积
printf("%d\n",sum);

}   

return 0;
}

差分

公 式 : 前 缀 和 : a [ n ] 公式:前缀和:a[n] :a[n]
差 分 : b [ n ] 差分:b[n] :b[n]
b [ i ] = a [ i ] − a [ i − 1 ] b[i]=a[i]-a[i-1] b[i]=a[i]a[i1]

      类似于求前缀和的逆运算,这次通过前缀和求得差分数组
      比较抽象
       菜鸡理解:
      已知一个前缀和序列a[n],
      向前缀和a[n]序列[l,r]中每一个数加上c,
      假想一个序列b[n]是构成a[n]的差分数组;
      那么要完成这一操作
      **只需要在b[l]+c;
      并且在b[r+1]-c**
      类似的,当l==r时,即向序列a[n]中插入一个数据;
       得到前缀和数组a[n];
      即递推公式a[i]-a[i-1]=b[i]可视作插入操作的一个特例;
      可利用这一性质反过来由前缀和得到差分数组

在这里插入图片描述

#include <iostream>
using namespace std;

const int N=100010;
int a[N],b[N];
int n, m;
void insert (int l,int r,int c){
b[l]+=c;
b[r+1]-=c;

}


int main(){

cin>>n>>m;

int l,r,c;

for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)insert(i,i,a[i]);//通过插入操作获得差分数组b[i],相当于利用了递推公式b[i]=a[i]-a[i-1];

while(m--){
cin>>l>>r>>c;
insert(l,r,c);
}
for(int i=1;i<=n;i++){
b[i]+=b[i-1];
printf("%d",b[i]);
}//利用普通前缀和公式,求出m次操作完之后的最终前缀和数组 ,此时b[i]为最终前缀和数组
//若定义新数组s[N][N]存放最终差分数组,那么这样写也正确s[i]=s[i-1]+b[i];

return 0;
}

差分矩阵

是对应的二阶差分数组,思路一致,注意是二维,写的时候脑子带图
在这里插入图片描述

#include <iostream>
using namespace std;

const int N=1010;

int a[N][N],b[N][N];//前缀和二维数组,差分二维数组

int n,m,q;

void insert(int x1,int y1,int x2,int y2,int c){//插入操作(核心)思路同上
    b[x1][y1]+=c;
    b[x1][y2+1]-=c;
    b[x2+1][y1]-=c;
    b[x2+1][y2+1]+=c;
    
}


int main(){
    cin>>n>>m>>q;

    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
       scanf("%d",&a[i][j]);//通过传值初始化a
    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
       insert(i,j,i,j,a[i][j]);//通过插入操作间接初始化b
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);//执行q次插入数据操作,得到最终差分数组
        
    }
    
    for(int i=1;i<=n;i++){//打印最终差分数组的前缀和数组
       for(int j=1;j<=m;j++){
           b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
           // s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+b[i][j];或者定义新数组s[N][N]用来存放最后的差分数组,那么这样写也正确
           printf("%d ",b[i][j]);
           
       }
       printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值