• (基础)--- 前缀和、差分


    一维前缀和

    顾名思义:前缀和就是数组前n项和

    注意:数组下标从1开始防止越界

    1、预处理前缀和数组
    2、用公式求区间和

    //求前缀和
    s[i] = s[i-1]+a[i];
    //求数组下标在l,r之间的元素之和
    s[r]-s[l-1]
    

    二维前缀和

    用二维矩阵来计算

    // 求s[i,j] 表示矩阵大小为行i,列j的元素之和
    s[i][j] = s[i-1][j]+s[i][j-1] - s[i-1][j-1] + a[i][j];
    // 求s[x1,y1]到s[x2,y2]之间的元素之和
    s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
    
    #include<iostream>
    
    using namespace std;
    const int N = 1010;
    
    int n,m,q;
    int a[N][N],s[N][N];
    
    int main(){
        cin >> n >> m >> q;
        for(int i = 1; i <= n; i ++ ){
            for(int j = 1; j <= m; j ++ ){
                cin>>a[i][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;
            cin>>x1>>y1>>x2>>y2;
            cout<<s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]<<endl;
        }
        return 0;
    }
    

    一维差分

    给定a[1],a[2],...a[n]构造差分数组b[N],使得a[i] = b[1]+b[2]+...+b[i]
    b[i]=a[i]-a[i-1];
    核心操作:将a[L~R]全部加上C,等价于:b[L]+=C,b[R+1] -= C;
    1、a[1~L-1]无影响
    2、a[L~R]加上了C
    3、a[R+1~N]无影响

    实现差分

    有的操作利用了前缀和,差分是前缀和的逆运算

    // b[N] 初始全为0
    void insert(int l,int r,int c){
        b[l]+=c;
        b[r+1]-=c;
    }
    //利用前缀和来还原数组数据
    for(int i = 1; i <= n; i ++ ) a[i] = a[i-1] + b[i];
    
    
    //整体操作:计算差分数组b[N],将序列中[l, r]之间的每个数加上c,还原原数组
    #include<iostream>
    
    using namespace std;
    const int N = 1e5+10;
    
    int n,m;
    int a[N],b[N];
    
    void insert(int l,int r,int c){
        b[l]+=c;
        b[r+1]-=c;
    }
    
    int main(){
        cin >> n >> m;
        for(int i = 1; i <= n; i ++ ) cin>>a[i];
        
        for(int i = 1; i <= n; i ++ ) insert(i,i,a[i]);
        
        while(m -- ){
        	int l,r,c;cin>>l>>r>>c;
        	insert(l,r,c);
    	}
        
        for(int i = 1; i <= n; i ++ ) a[i] = a[i-1] + b[i];
        
        for(int i = 1; i <= n; i ++) cout<<a[i]<<" ";
    }
    

    二维差分

    给定原矩阵a[i,j],构造差分矩阵b[i,j],使得a[][]是b[][]的二维前缀和

    二维差分核心操作

    给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有数a[i,j],加上C。

    //对于差分数组的影响:
    
    b[x1,y1] += C;
    b[x1,y2+1] -=C;
    b[x2+1,y1] -= C;
    b[x2+1,y2+1] +=C;
    
    #include<iostream>
    
    using namespace std;
    const int N = 1e3+10;
    
    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(){
    	cin >> n >> m >> q;
    	for(int i = 1; i <= n; i ++ ){
    		for(int j = 1; j <= m; j ++ ){
    			cin>>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 ++ ){
    			a[i][j] = a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j];
    		}
    	}
    	
    	for(int i = 1; i <= n; i ++){
    		for(int j = 1; j <= m; j ++ ){
    			cout<<a[i][j]<<" ";
    		}
    		puts("");
    	}	
    } 
    
  • 相关阅读:
    Android编译环境配置(Ubuntu 14.04)
    Android中的接口回调技术
    我为什么要拒绝Ctrl+C和Ctrl+V?
    软件设计网站大全
    国内及Github优秀开发人员列表
    Linux常用指令
    Linux系统目录结构
    UML图
    Android软件设计---Dumpsys工具使用
    Android应用程序Monkey测试
  • 原文地址:https://www.cnblogs.com/bingers/p/13546741.html
Copyright © 2020-2023  润新知