acwing 笔记 前缀和 和 差分

对于数组a[n]

用s数组来记录, s[i]=a1+a2+a3.....+ai;

注意:前缀和下标要从一开始

1.那么如何求s[i]

2.s[i]用来干什么

1.for(int i=1;i<=n;i++)

     { 

     s[i]=a[i]+s[i-1];

    }

2.作用:快速求a[l] 到a[r]的和,即s[r]-s[l-1]

 将时间复杂度由o(n) 降低到 o(1)

代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n ,m,r,l;
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--)
  {
       scanf("%d%d",&l,&r); 
       printf("%d\n",s[r]-s[l-1]);
  }
  } 

二维前缀和

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int n,m,k;
int a[N][N],s[N][N];
int main()
{   scanf("%d%d%d",&n,&m,&k);
   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++)
   {
       s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
   }
}
   while(k--)
   { 
    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;
 } 

下面是差分,差分与前缀和互为逆运算,

对于已知数组a提供一个b数组

使得b数组的前缀和是a,那么就说b是a的差分

差分的作用 用o(n)时间,由b数组得到a数组

对于给定区间[l,r]让a数组+c,时间复杂度o(n) ,用差分来做就只用o(1)

方法:让b[l]+c,b[r+1]-c

同时,对于a数组,可以看出数组内全是零,读入数组可以看出是差分数组b进行了n次插入,每次插入,对于a1则是b[1]+c,b[2]-c

这样就不用考虑差分数组是怎么来的了

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+10;

int a[N],b[N];
int n,m;
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]);
}
 

下面是二维差分

下面是代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e3+10;
int n,m,p;
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,&p);
    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(p--)
    {   int z,x,c,v,y;
       scanf("%d%d%d%d%d",&z,&x,&c,&v,&y);
        insert(z,x,c,v,y);
    }
    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];
        }
    }
    
        for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
          printf(" %d",b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值