基本算法——前缀和与差分
一、前缀和
一维前缀和
顾名思义,不再赘述。
#include#include #include using namespace std; const int N =1e6+10; int n,m; int a[N],sum[N]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; } while(m--) { int l,r;scanf("%d%d",&l,&r); printf("%d\n",sum[r]-sum[l-1]); } return 0; }
二维前缀和
类似于容斥原理,手动画图很好理解。
#include#include #include #include using namespace std; const int N = 1010; int a[N][N],sum[N][N]; int n,m,q; int main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]; } while(q--) { int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2); printf("%d\n",sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]); } return 0; }
二、差分
差分可以说是前缀和的逆运算。
设原序列为a1,a2,…an,则该序列的差分序列b1,b2,…,bn满足如下条件:ai = b1 + b2 + … + bi。
一维差分
#include#include #include using namespace std; const int N = 1e5+10; int a[N],b[N]; int n,q; int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]-a[i-1]; } while(q--) { int l,r,c; scanf("%d%d%d",&l,&r,&c); b[l]+=c;b[r+1]-=c; } int sum=0; for(int i=1;i<=n;i++) { sum+=b[i]; printf("%d ",sum); } return 0; }
二维差分
#include#include #include using namespace std; const int N =1010; int a[N][N],b[N][N]; int n,m,q; int main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); b[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]; } while(q--) { int x1,y1,x2,y2,c; scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c); b[x1][y1]+=c; b[x2+1][y1]-=c; b[x1][y2+1]-=c; b[x2+1][y2+1]+=c; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j]; printf("%d ",a[i][j]); } printf("\n"); } return 0; }
附链接
一维前缀和
二维前缀和
一维差分
二维差分