差分问题总结
一维例题:
输入一个长度为n的整数序列。
接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。
请你输出进行完所有操作后的序列。
设
那么
求a数组时,就可以利用b数组的前缀和来计算
在a2-a4区间内每个数加x,就相当于b2加上2,而b3不变,b4也不变,b5要减去2,也就是
在l r区间内加x,那么就b[l]+=x b[r+1]-=x
那么上面的题就可以内解决了,利用差分思想。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=200000+66;
int a[maxn];
int b[maxn];
void add(int l,int r,int x)
{
b[l]+=x;
b[r+1]-=x;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(b,0,sizeof(b));
rep(i,1,n)
{
cin>>a[i];
add(i,i,a[i]);
}
while(m--)
{
int l,r,x;
cin>>l>>r>>x;
add(l,r,x);
}
rep(i,1,n)
{
b[i]+=b[i-1];
cout<<b[i]<<" ";
}
cout<<endl;
}
}
二维例题
输入一个n行m列的整数矩阵,再输入q个操作,每个操作包含五个整数x1, y1, x2, y2, c,其中(x1, y1)和(x2, y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上c。
请你将进行完所有操作后的矩阵输出。
用差分数组b[][]的前缀和来代表数组a[][]
子矩形左上角和右下角坐标分别为(x1,y1)和(x2,y2),那么对子矩形操作时,b数组的变化为
b[x1][y1]+=x
b[x1][y2+1]-=x
b[x2+1][y1]-=x
b[x2+1][y2+1]+=x
求出最终结果时,就求出其前缀和即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=2000+66;
int a[maxn][maxn];
int b[maxn][maxn];
void add(int x1,int y1,int x2,int y2,int x)
{
b[x1][y1]+=x;
b[x2+1][y2+1]+=x;
b[x1][y2+1]-=x;
b[x2+1][y1]-=x;
}
int main()
{
int n,m,q;
while(cin>>n>>m>>q)
{
rep(i,1,n)
{
rep(j,1,m)
{
int x;
cin>>x;
add(i,j,i,j,x);
}
}
while(q--)
{
int x1,y1,x2,y2,x;
cin>>x1>>y1>>x2>>y2>>x;
add(x1,y1,x2,y2,x);
}
rep(i,1,n)
{
rep(j,1,m)
{
a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j];
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
}
前缀和问题总结
一维前缀和例题
问题 1882: [蓝桥杯][2017年第八届真题]k倍区间
时间限制: 1Sec 内存限制: 128MB 提交: 489 解决: 107
题目描述
给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
你能求出数列中总共有多少个K倍区间吗?
思路:也就是求多少个i,j对数(i<j),使得(sj-si)%k=0,也就是sj%k=si%k。
那么我们枚举j位置,求出cnt[s[j]]就可啦,答案加上它。最后的时候答案再加上cnt[0]就行啦,因为可能有某段si直接可以整除k。
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#include<string.h>
using namespace std;
const int maxn=200000+66;
int a[maxn];
int cnt[maxn];
int s[maxn];
int main()
{
int n,k;
while(cin>>n>>k)
{
rep(i,1,n)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
s[i]%=k;
}
ll ans=0;
rep(i,1,n)
{
//枚举j位置
ans+=cnt[s[i]];
cnt[s[i]]++;
}
cout<<ans+cnt[0]<<endl;
}
}