前缀和与分差【算法基础】

一、一维前缀和

数组:a1,a2,a3……an

前缀和:Si=a1+a2+……+ai

利用前缀和,可以求区间[l,r]的和。

步骤:

(1)先求出前缀和数组{S1,S2,S3……Sn}

(2)用公式求区间和S[r ]-S[l-r]

模板:

#include 
using namespace std;
const int N =100010;

int n,m;//n:整数个数,
int a[N],s[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++)s[i]=s[i-1]+a[i];
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",s[r]-s[l-1]);
    }
    return 0;
}

二、二维前缀和

方法步骤:

(1)求出前缀和数组S[0][0]......S[i][j]

 s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1]

(2)根据公式求区间和

s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]

代码模板: 

#include
using namespace std;
const int N=1010;
int n,m,q;//n行m列 问q组
int s[N][N];//会被初始化为0
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)//注意是从1开始
        for(int j=1;j<=m;j++)
            scanf("%d",&s[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];

    while(q--)
    {
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);

    }
    return 0;
}

三、差分

差分其实就是前缀和的逆运算

数组:a1,a2,a3……an

构造:b1,b2,b3,……bn

使得ai=b1+b2+……+bi

则称a是b的差分,b是a的前缀和。

模板:

#include
using namespace std;
const int N=100010;
int n,m;
int a[N],b[N];
void insert(int l,int r,int c)//对a[l,r]的元素+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]);//把a看成前缀和数组
    
    for(int i=1;i<=n;i++)insert(i,i,a[i]);//a数组每个元素相当于对[i,i]区间的元素+a[i]
    //[1,1]+a[1]、[2,2]+a[2]……
    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];//b变回前缀和数组
    for(int i=1;i<=n;i++)printf("%d ",b[i]);
    
    return 0;
}

你可能感兴趣的:(基础算法,算法)