zoukankan      html  css  js  c++  java
  • 前缀和、二维前缀和与差分

    前缀和

    假如给出一串长度为n的数列a1,a2,a3...an,再给出m个询问,每次询问给出L,R两个数,要求给出数列在区间[L,R]的和

    普通的方法,时间复杂度为O(n*m)

    int a[100005];
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int sum=0;
    while(m--){
        for(int i=L;i<=R;i++){
            sum+=a[i];
        }
    }
    

    前缀和就是前面i个数的总和,对于每个询问,只需要输出a[R]-a[L-1]即可
    用前缀和的方法,时间复杂度O(m+n)
    前缀和求法

    int a[0]=0;
    for(int i=1;i<=n;i++){
        a[i]+=a[i-1];
    }
    

    差分

    假如给出一串长度为n的数列a1,a2,a3...an,再给出m次以及不同的L和R[L,R]操作
    操作一:将[L,R]内的元素都加上P
    操作二:将[L,R]内的元素都减去P
    最后求[L,R]内的元素之和

    普通方法时间复杂度为O(m*n)

    利用差分+前缀和

    #include <bits/stdc++.h>
    using namespace std;
    const int manx=1e5+5;
    int a[maxn],b[maxn];
    int main(){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=m;i++){
            int l,r,t,p;//t为操作类型,p为加减的大小
            cin>>t>>l>>r>>p;
            if(t==1){//t==1表示加
                b[l]+=p;b[r+1]-=p;//因为操作一我只需对[L,R]区间里的数加p,[R+1,n]这个区间里的数没必要加p,所以需要减掉p。
            }else{//t==0表示减
                b[l]-=p;b[r+1]+=p;
            }
        }
        int add=0;
        for(int i=1;i<=n;i++){
            add+=b[i];
            a[i]+=a[i-1]+add;
        }
        cin>>l>>r;
        printf("%d
    ",a[r]-a[l-1]);
        return 0;
    }
    

    裸差分

    第一行输入两个整数n,q。(1<= n, q <= 1e5)接下来q行,
    每行输入两个整数l, r(l <= r),表示andy让标号落在区间[l, r]里的数高度都加1
    输出所有数的现状

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn=1e5+10;
    int a[maxn],b[maxn];
    int main(){
        int n,q;
        cin>>n>>q;
        while(q--){
            int l,r;
            scanf("%d%d",&l,&r);
            b[l]++;
            b[r+1]--;
        }
        for(int i=1;i<=n;i++){
            a[i]+=a[i-1]+b[i];
        }
        for(int i=1;i<=n;i++){
            printf("%d ",a[i]);
        }
        putchar('
    ');
    
        return 0;
    }
    

    二维前缀和

    给定一个n*m大小的矩阵a,有q次询问,每次询问给定x1,y1,x2,y2四个数,求以(x1,y1)为左上角坐标和(x2,y2)为右下角坐标的子矩阵的所有元素和。注意仍然包含左上角和右下角的元素。

    二维前缀和求法
    n行m列

    memset(a,0,sizeof(a));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];//因为a[i-1][j-1]的值被加了两次
        }
    }
    

    1 2 3
    2 1 2
    2 1 1
    前缀和
    1 3 6
    3 6 11
    5 9 15

  • 相关阅读:
    软工实践寒假作业(2/2)
    Java 内存溢出分析
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件测评
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次作业-疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
    配合springboot的快速运维脚本
  • 原文地址:https://www.cnblogs.com/Emcikem/p/11351353.html
Copyright © 2011-2022 走看看