差分就是将数列中的每一项分别与前一项数做差,异或也满足,例如:
一个序列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) (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]
c[1,n]都为相等即可
2,因为
∑
i
=
1
n
+
1
c
i
=
0
\sum_{i=1}^{n+1} c{_i}=0
∑i=1n+1ci=0,而一开始
c
1
c{_1}
c1一定大于0,所以说,每个正的
c
i
c{_i}
ci都有一个负的
c
j
+
1
c{_{j+1}}
cj+1相对应,只需要统计正的
c
i
c{_i}
ci的和即可。
二维前缀和
例题: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;
}