前缀和和差分算法

         前缀和准确来说并不是一种算法,应该算是一种思想,即如果要计算一个一维数组的[l,r]区间内的数的总和,可以计算该数组的所有前缀和数组s[ ],在使用s[l,r] = s[ l ] - s[r - 1]就可以计算这个数组之中的总和就可以了!

        前缀和算法的模板(一维数组版)

int front_count(int l,int r,int q[]){
    int s[]; 
    for (int i = 1;i <= length(q);i++) s[i] = s[i - 1] + a[i];
    
    //计算区间内的总和
    return s[r] - s[l - 1]; 
}

        前缀和的边界问题

        1. 为什么使用s[ r ] - s[ l - 1]?

                原因:主要为了不用判断是否到了最后一个数,因为前面一个数就是零,减去对结果并没有影响,这样设置的话就可以使得这个公式被所有的区间适用,不用进行边界问题的判断。

        前缀和算模板二(二维数组版)、

        

int doubleFront_count(int x1,int y1,int x2,int y2,int q[][]){
    int len = length(q);
    int s[][];
    //计算前缀和,主要是研究适用公式
    for (int i =1;i <= len;i++){
        for (int j= 1;j <= len;j++){
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + a[i][j];
        }
    }
    
    //直接使用x和y进行定位计算前缀和就可以了
    return s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1][y1];
}

差分算法

        差分算法准确来说也是这一种思想,就是前缀和的逆运算,前缀和是:s[i] = s[i - 1] + a[i];

而差分就是使用s数组来表示a[ i ];通过等式关系可以知道a[i] = s[i] - s[i- 1];

       差分的作用

        当需要对a数组的每一个数进行加某个一样的操作的时候,就可以通过差分数组的首元素的操作就可以将a数组的所有数加上这个数;

         原因 

               核心思想:差分数组的前缀和就是原数组

                设置数组b[ ]是a[ ]的差分数组,那么进行前缀和的时候,都会加上差分数组的第一个首元素,所以当第一个数组加上一个数的时候就会使得,后面的所有前缀和都要加上这个数,即原数组 a 的每一个数加上这个数,然后再后面一个数减去这个数,就可以将这个区间之后的所有数减去这个加数,这样就可以等到这个这个区间内的所有数加上一个数的结果了;

        差分数组的模板(一维数组版本)

        

int[] differ_separate(int l,int r,int c){
    int num[],b[i];


    for (int i = q;i <= length(q);i++){
        scanf("%d",&num[i]);
        b[i]= num[i] - num[i - 1];
    }

    //直接将第一个数加c,区间的最后一个的下一个数减c就可以了
    b[l] += c;
    b[r + 1] -= c;


    //使用前缀和等到处理之后的原数组
    for (int i = l;i < =r;i) b[i] += b[ i - 1];
    return b[]; 
}
        二维差分数组

        根据上面的前缀和的公式:s[ i ][ j ] = s[i - 1][ j ] + s[ i ][ j -1 ] - s[ i- 1 ][ j - 1 ] + a[ i ][ j ];

        可以逆推出a[i][j] = s[ i ][ j ] - (s[i - 1][ j ] + s[ i ][j -1] - s[i- 1][j - 1]);

        然后区间内第一个加上这个数,区间内最后一个数减去这个数就可以了

        差分数组的模板(二维数组版)
void differ_double (int x1,int y1,int x2,int y2){
    int a[][],b[][];
    
    for (int i = 1;i <= length(a);i++)
        for (int j = 1;j <= length(a[i]);j++)
            scanf("%d",&a[i][j]);

    //使用b数组求得a数组的差分数组
    for (int i = 1;i <= length(a);i++)
        for (int j = 1;j <= length(a[i]);j++)
            b[i][j] = a[i][j] - a[i- 1][j] - a[i][j-  1] + a[i - 1][j- 1];
     
    //使用差分数组的性质,在指定位置加上一个数,在将受影响的位置进行抵消 就可以了
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;

    for (int i = 1;i <= length(a);i++)
        for (int j = 1;j <= length(a[i]);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 <= length(a);i++)
        for (int j = 1;j <= length(a[i]);j++)
            printf("%d",a[i]j[j]);
       
}

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GK742

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值