差分的总结
其实差分就是前缀和的逆运算,通过前缀和的相减可以得到数组的原值
一维差分,给定一个前缀和序列a,我们可以通过计算得到它的差分序列
这里差分序列b定义为: b[1]=a[1],b[i]=a[i]-a[i-1];
我们可以通过差分来实现区间操作,若要把a的区间[l,r]加d,就可以通过b[l]+d,b[r+1]-d的操作实现,
AcWing 797. 差分
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]-a[i-1];//处理为差分序列
}
//差分就是把原数组作为差分的前缀和。
while(m--)
{
int l,r,c;
cin>>l>>r>>c;
b[l]+=c;
b[r+1]-=c;
}
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1];
cout<<b[i]<<" ";
}
return 0;
}
AcWing 100. IncDec序列
这个题让我们用最少的操作次数使得a数组都一样,转化思想就是让差分序列b都为0,b[1]等于a[1];
我们在做b[l]++,b[r+1]--;操作的时候,要找两个数配对,那么负数++,正数--,是不是就最快了。这就是第一种操作,如果b中同时存在正数和负数,优先考虑这个操作
但是做完之后可能还不行,如果正负数个数不等的话就需要继续操作
然后继续操作非零数
我们假设有正数和为p,负数和为q,那么第一种操作最多会进行min(p,q)次,然后我们继续操作剩余的次数abs(p-q),取绝对值
那最后会有多少种结果?
前面两两配对的操作最后只可能得到一种结果,后面的纯正负需要操作abs(pos-neg)次,b[1]可以是任意数,所以最后就是abs(p-q)+1种结果
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]-a[i-1];
}
long long p=0,q=0;
for(int i=2;i<=n;i++)
{
if(b[i]>0) p+=b[i];
else q-=b[i];
}
cout<<min(q,p)+abs(q-p)<<endl;//这里输出max(q,p)就可以了
cout<<abs(q-p)+1;
return 0;
}
AcWing 4262. 空调
这个和上个题是类似的
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int p[N];
int m[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>p[i];//理想温度数组
}
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
p[i]-=t;//这里得到与理想温度的差值。
//类似Indec序列,最少次数把p变为0;
}
/*
for(int i=n;i>1;i--)
{
p[i]=p[i]-p[i-1];
}
*/
for(int i=1;i<=n;i++)
{
m[i]=p[i]-p[i-1];
}
//然后统计正负数数量
long long r=0,q=0;
for(int i=1;i<=n;i++)
{
if(m[i]>0) r+=m[i];
else q-=m[i];
}
cout<<max(r,q);
return 0;
}
AcWing 798. 差分矩阵
二维差分模板题
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int b[N][N],a[N][N];
void insert(int x1,int y1,int x2,int y2,int c)//实现差分数组
{
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
int main()
{
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
insert(i,j,i,j,a[i][j]);
}
}
while(q--)
{
int x1,x2,y1,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
insert(x1,y1,x2,y2,c);
}
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];//求二维前缀和
cout<<b[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
洛谷P3397地毯
做完上个题如果怕没有掌握可以做做这个题,意思非常简单
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N];
void insert(int x1,int y1,int x2,int y2,int c)
{
a[x1][y1]+=c;
a[x1][y2+1]-=c;
a[x2+1][y1]-=c;
a[x2+1][y2+1]+=c;
}
int main()
{
int n,m;
cin>>n>>m;
while(m--)
{
int x1,x2,y1,y2;
int c=1;
cin>>x1>>y1>>x2>>y2;
insert(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
AcWing 5396. 棋盘
这个思路很好想,二维差分,改变一定区间内数组的值,如果被翻转偶数次就仍为白子,奇数次为黑子
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N];//直接以a作为棋盘的差分矩阵。
int n,m;
void change(int x1,int y1,int x2,int y2,int c)
{
a[x1][y1]+=c;
a[x2+1][y1]-=c;
a[x1][y2+1]-=c;
a[x2+1][y2+1]+=c;
}
int main()
{
cin>>n>>m;
int c=1;
while(m--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
change(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
if(a[i][j]%2==0) cout<<"0 ";
else cout<<"1 ";
}
cout<<endl;
}
return 0;
}
AcWing 4655. 重新排序
这里还用到了排序不等式的知识,不懂得可以去学习一下
这里记录每个位置被计算的次数,然后计算sum1,之后进行排序,也就是让计算次数最大的位置放最大的数,依次递减。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e5+5;
int a[N];
int b[N];//用来修改每个位置会被计算多少次
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int m;
cin>>m;
ll sum1=0;
ll sum2=0;
while(m--)
{
int l,r;
cin>>l>>r;
b[l]++;
b[r+1]--;
}
for(int i=1;i<=n;i++) b[i]+=b[i-1];//差分数组求前缀和转为次数数组
for(int i=1;i<=n;i++)
{
sum1+=(ll)b[i]*a[i];
}
sort(b+1,b+n+1);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
sum2+=(ll)a[i]*b[i];
}
cout<<sum2-sum1;
return 0;
}
AcWing 3729. 改变数组元素
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
memset(a,0,(n+1)*4);
for(int i=1;i<=n;i++){
int x;
cin>>x;//x即为题目中的a[i];
x=min(x,i);
int l=i-x+1,r=i;
a[l]++,a[r+1]--;
}
for(int i=1;i<=n;i++) a[i]+=a[i-1];
for(int i=1;i<=n;i++) cout<<!!a[i]<<" ";
cout<<endl;
}
return 0;
}
AcWing 101. 最高的牛

浙公网安备 33010602011771号