算法基础——前缀和及差分

一、前缀和——基本就是公式(容斥原理)

 
 

 一维前缀和数组

将S0定义成0是为了边界处理,统一形式。比如求 [1,10]的前缀和,其实就是S10,但是当我们定义S0 = 0后,我们就依然可以表示为 S10 - S0
复制代码
#include<iostream>
using namespace std;
const int N  = 100010;
int n,m;
int a[N],b[N];  //原数组和前缀和数组

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
    //前缀和数组
    for(int i = 1;i <= n;i ++) b[i] = b[i-1] + a[i];
    while(m--){
        int l,r;
        scanf("%d%d",&l,&r);
        cout<<b[r] - b[l-1]<<endl;
    }
}
复制代码

 

 

二维前缀和矩阵

 

 

前缀和问题一般是从1开始
复制代码
#include<iostream>
using namespace std;

const int N = 1010;
int n,m,q;
int a[N][N],b[N][N];

int main(){
    scanf("%d%d%d",&n,&m,&q);
    
    for(int i = 1;i <= n;i++)
        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++)
            b[i][j] =  b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j];
    while(q--){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        cout<<b[x2][y2] - b[x2][y1 -1] - b[x1 -1][y2] + b[x1-1][y1-1]<<endl;
    }
            
    // for(int i =1;i <= n;i++){
    //     for(int j = 1;j <= m;j++)
    //         printf("%d ",b[i][j]);
    //         puts("");
    // }    
     return 0;   
}
复制代码

 

 

  

 

二、差分

一维差分

其实 a[i] 就是差分数组b[1]...b[ i ][的前缀和
下面使构造方式,简单一看(不用管)
 
复制代码
#include<iostream>
using namespace std;

const int N = 100010;
int n,m;
int a[N],b[N];  //y原数组和差分数组

//指定区间[l,r]加c,只需要使b[l] +c ,b[r+1] -c即可
void insert(int l,int r,int c){
    b[l] += c;
    b[r+1] -= c;
}

int main(){
    scanf("%d%d",&n,&m);
    
    for(int i = 1;i <= n;i++) scanf("%d",&a[i]); 
    
    for(int i = 1;i <= n;i++) insert(i,i,a[i]);  //做原数组的差分数组
    
    while(m--){
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        insert(l,r,c);
    }
    
    for(int i = 1;i <= n;i ++) b[i] += b[i-1];   //求前缀和
    for(int i = 1;i <= n;i ++) printf("%d ",b[i]);
    
    return 0;
}
复制代码

 

开始时不需要考虑如何构造,将其看为0,然后再插一遍就可以了
 
 

二维差分矩阵

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
其中 b[i][j]是提前假定好的,性质就是构造b,使得h二维数组a是二维数组b的前缀和
 
复制代码
#include<iostream>
using namespace std;

const int N = 1010;
int n,m,q;

int a[N][N],b[N][N];  //存放原矩阵和差分矩阵

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(){
    scanf("%d%d%d",&n,&m,&q);
    
    for(int i = 1;i <= n;i++)
        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++)
            insert(i,j,i,j,a[i][j]);
            
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);
    }
    
    //求前缀和
    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];
            printf("%d ",b[i][j]);
        }   
        cout<<endl;
    }
    
    return 0;
}
复制代码

 

 感谢y总!

posted @   Uitachi  阅读(628)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示