差分和前缀和

差分就是将数列中的每一项分别与前一项数做差,例如:

一个序列1 2 5 4 7 3,差分后得到1 1 3 -1 3 -4 -3

这里注意得到的差分序列第一个数和原来的第一个数一样(相当于第一个数减0)

差分序列最后比原序列多一个数(相当于0减最后一个数)

性质:

1、差分序列求前缀和可得原序列

2、将原序列区间[L,R]中的元素全部+1,可以转化操作为差分序列L处+1,R+1处-1

3、按照性质2得到,每次修改原序列一个区间+1,那么每次差分序列修改处增加的和减少的相同
————————————————
版权声明:本文为CSDN博主「婷霸」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Healer66/article/details/87201014

给定一个序列,每次可以选择区间 ( a , b ) (a,b) 使数字加一或者减一,问多少次操作可使序列中的数都相等。在保证相等的情况下,最终序列有多少种情况。

#include<stdio.h>
int main()
{
    int n;cin>>n;
    int a[n+1];
    for(int i = 1;i <= n ;++i)
        scanf("%lld",&a[i]);
    for(int i = 1;i <= n; ++i)
        b[i] = a[i]-a[i-1];
    LL sum1,sum2;
    sum1 = sum2 = 0;   
    for(int i = 2;i <= n; ++i)//从i=2开始统计,保证(1,n)相等,不一定为0。
        if(b[i] > 0)
            sum1 += b[i];
        else
            sum2 += abs(b[i]);
    cout<<max(sum1,sum2)<<endl;//如果负数多,正数可以全部抵消完,然后再处理负数,如果是正数多也一样。
    cout<<abs(sum1-sum2)+1<<endl;如果正数负数一样多,保证最少操作的前提下只有一种情况,如果最后负数多,可以从后往前处理,也可从前往后处理
    左一次操作,右零次操作,列举得到答案。
   return 0;
}

其他例题
挤牛奶Milking Cows
扑克牌型
思路:1.与第一个例题类似,不过要求是处理后序列数字全部为0,则差分 c [ 1 , n ] c[1,n] 都为相等即可
2,因为 i = 1 n + 1 c i = 0 \sum_{i=1}^{n+1} c{_i}=0 ,而一开始 c 1 c{_1} 一定大于0,所以说,每个正的 c i c{_i} 都有一个负的 c j + 1 c{_{j+1}} 相对应,只需要统计正的 c i c{_i} 的和即可。

二维前缀和

引用一篇博客

例题:Painting The Barn S
题解:

#include<iostream>
using namespace std;
int n,k,ans,c[1010][1010],a[1010][1010];
//n,k意义如题,ans是答案,c是差分数组,a是原数组
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        c[x1][y1]++;//二维差分区间加
        c[x2][y2]++;//
        c[x1][y2]--;//
        c[x2][y1]--;//
    }
    for(int i=0;i<=1005;i++)
        for(int j=0;j<=1005;j++)
        {
            a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+c[i][j];//前缀和的递推式
            if(a[i][j]==k)ans++;//恰被覆盖k次,统计
        }
    cout<<ans<<endl;
    return 0;
}
发布了16 篇原创文章 · 获赞 2 · 访问量 618

猜你喜欢

转载自blog.csdn.net/csdn_ggboy/article/details/104329727