差分数组与前缀和

  1. 前缀和
    前缀和顾名思义就是前面i个数的总和。
    假设有一个序列A,前缀和为S。根据概念很容易知到公式
    \(S[i]=\displaystyle \sum_{j=1}^iA[j]\)

    如何求区间\([l,r]\)的和呢?
    \(sum[l,r]=s[r]-s[l-1]\)

    那如果要对多个不同区间

    \([l,r]\)进行加减操作呢?然后输出某个区间\([l,r]\)的区间和,接下来就要用到差分数组了

  2. 差分数组

    设原数组为\(A[i]\),差分数组为\(B[i]\),则:

    \[B[i]=\begin{cases} A[i]&i=1\\ A[i]-A[i-1]&i\geq2 \end{cases}\]

    差分数组的性质:

    • 如果对区间\([l,r]\)进行修改,只需修改\(B[l],B[r+1]\)(\(B[l]\)加上修改值,\(B[r+1]\)减去修改值)

    • \(A[i]=\displaystyle \sum_{j=1}^{i}B[j]\)(通过\(B[i]=A[i]-A[i-1]\)证明)

    • $S[x]=\displaystyle \sum_{i=1}^{x}A[i]=\displaystyle \sum_{i=1}^{x} \displaystyle \sum_{j=1}^{i}B[j]=\displaystyle \sum _{i=1}^{x}(x-i+1)*B[i] $


有n个数。m个操作,每一次操作,将x~y区间的所有数增加z;

最后有q个询问,每一次询问求出x~y的区间和。

设原数组为\(A[i]\)

步骤:

  • 先求出差分数组\(B[i]=A[i]-A[i-1]\)
  • 在根据\(m\)个造作修改\(B[i]\)
  • 求修改后的\(A[i]=A[i-1]+B[i]\)
  • 求前缀和\(S[i]=S[i-1]+A[i]\)
  • 最后输出区间和\(sum[x,y]=S[y]-S[x-1]\)

举个栗子 航班预订统计

这道题很简单,没有要求输出区间和,也不用先求出差分数组

#include<iostream>
using namespace std;
int n;  //n个航班
int i;  //i条预定记录
int b[20005];   //差分数组

int main()
{
    cin>>n>>i;
    for(int j=0;j<i;j++)
    {
        int x,y,z;  //[x,y]预定了z个座位
        cin>>x>>y>>z;
        b[x]+=z;
        b[y+1]-=z;
    }
    for(int k=1;k<=n;k++)
    {
        b[i]+=b[i-1];
        cout<<b[i]<<' ';
    }
    
}

前面都是一维前缀和,再举个一位前缀和的栗子 最大子矩阵

没有涉及区间修改,只是求前缀和

#include<iostream>
#include<algorithm>
using namespace std;
int m,n;    //整数矩阵
int x,y;    //所求子矩阵的长和宽
int b[1000][1000];
int ans;

int main()
{
    cin>>m>>n>>x>>y;
    int t;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
        {
            cin>>t;
            b[i][j]+=b[i-1][j]+b[i][j-1]+b[i-1][j-1]+t;
            if(i>=x&&j>=y)
                ans=max(ans,b[i][j]-b[i-x][j]-b[i][j-y]-b[i-x][j-y]);                
        }
    cout<<ans<<endl;
}
上一篇:RNN识别PTB数据代码精解


下一篇:Summation Order