目录
一、前言
对于学计算机的同学来说,学习算法是一件非常重要的事情,废话不多讲,我们来讲讲“前缀和与差分问题”。
二、一维前缀和
所谓前缀和可以理解为数学里的数列前n项和,是用来求子区间和的一种便捷方法。
1、构造数组
对于所给的一维数组 a[n],我们先要构造其前缀和数组 s[n]。按照前缀和的定义我们很容易就能想到:
s[n-1]=a[0]+a[1]+......+a[n-1]
s[n]=s[n-1]+a[n]
显然我们不难想到,查询 i 到 j 这段子区间和就是:s[j]-s[i-1]
#include<iostream>
using namespace std;
#define n 100
int a[n],s[n];
int main(){
//构造前缀和数组
for(int i=1;i<=10;i++){
cin>>a[i];
s[i]=s[i-1]+a[i];
}
return 0;
}
2、上题例
P1147 连续自然数和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
3、C++代码
#include<iostream>
using namespace std;
#define n 2000002
int a[n],s[n];
int main(){
//构造前缀和数组
long long int M;
cin>>M;
for(int i=1;i<=M;i++){
a[i]=i;
s[i]=s[i-1]+a[i];
}
for(int i=1;i<M;++i){
for(int j=i+1;j<=M;++j){
if(s[j]-s[i-1]==M){
cout<<i<<" "<<j<<endl;
}
}
}
return 0;
}
该代码不能全部AC,有两个样例时间超限了,但这已经足够体现前缀和算法思想的正确性。
4、python代码
M=int(input())
s=[0 for _ in range(M+2)]
for i in range(1,M+1):
s[i]=s[i-1]+i # 构造前缀和数组
for i in range(1,M):
for j in range(i+1,M+1):
if s[j]-s[i-1]==M:
print("{} {}".format(i,j))
三、一维差分
所谓差分可以理解为前缀和的逆运算,就是将数列中每一项分别与前一项做差。
1、构造数组
对于所给的一维数组 a[n],我们先要构造其一维差分数组 d[n]。按照差分的定义我们很容易就能想到:d[n] = a[n] - a[n-1]
在差分数组中,有一个非常重要的性质:
在数组范围 [L, R] 加上一个数 v,等价于 d[L]+v、d[R+1]-v
因为在差分数组中,标记位加了一个数,还原成原数组的时候,后面的数都会累加,然后要在 R+1 位再减去这个数停止累加
#include<iostream>
using namespace std;
#define n 5
int a[n+2],d[n+2];
int main(){
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;i++) // i从 1 或 2 开始都行
d[i]=a[i]-a[i-1]; //构造差分数组
for(int i=1;i<=n;++i)
cout<<d[i]<<" ";
return 0;
}
2、上题例
P2367 语文成绩 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
3、python代码
n,p=map(int,input().split())
a=[0 for _ in range(n+2)]
d=[0 for _ in range(n+2)]
line=list(map(int,input().split()))
for i in range(1,n+1):
a[i]=line[i-1]
d[1]=a[1]
for i in range(2,n+1):
d[i]=a[i]-a[i-1]
for _ in range(p):
x,y,z=map(int,input().split())
d[x]+=z
d[y+1]-=z
min=d[1]
for i in range(2,n+1):
d[i]+=d[i-1]
if d[i]<min:
min=d[i]
print(min)
该代码还差最后一个样例没过,主要是python内存会爆,但是同样逻辑的C++代码便可通过全部样例
4、C++代码
#include<iostream>
using namespace std;
int a[5000002],d[5000002];
int main(){
int n,p;
cin>>n>>p;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;i++) // i从 1 或 2 开始都行
d[i]=a[i]-a[i-1]; //构造差分数组
int x,y,z;
for(int i=0;i<p;++i){
cin>>x>>y>>z;
d[x]+=z;
d[y+1]-=z;
}
int min=d[1];
for(int i=2;i<=n;++i){
d[i]+=d[i-1];
if(d[i]<min){
min=d[i];
}
}
cout<<min<<endl;
return 0;
}
以上,一维前缀和与一维差分
祝好
(这里挖个坑,python能否找出一个一个输入,又能以空格为结束的方法,日后看到记得搞定)