目录
一、前缀和
1、前缀和作用
降低查询时的时间复杂度。例如:有个数,从开始求和到,即,如果暴力计算个和的时间复杂度为;采用前缀和计算,每次计算的为,时间复杂度为。
2、一维前缀和代码
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + a[i];
}
3、二维前缀和代码(容斥原理)
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] + a[i][j] - b[i - 1][j - 1];
}
}
二、差分
1、差分作用
前缀和的逆运算,减轻数据间的不规律波动。例如:对数组中某一个区间递加,可以先对这段区间求差分,再进行前缀和操作。
2、几种常见的差分
常数差分:
int a[N],b[N];
int l,r,k,n;
scanf("%d%d%d%d",&l,&r,&k,&n);
a[l] += k;
a[r + 1] -= k;
for(int i = 1;i <= n;i ++){
b[i] = a[i] + b[i - 1];
}
等差数列差分:
int a[N],b[N];
int l,r,a0,d,n;
scanf("%d%d%d%d%d",&l,&r,&a0,&d,&n);
a[l] += a0;
a[l + 1] += d - a0;
a[r + 1] -= a0 + (r - l + 1)*d;
a[r + 2] += a0 + (r - l)*d;
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + a[i];
}
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + b[i];
}
平方数列差分:
int a[N],b[N];
int l,r,a0,n; //a0表示平方数列的第一项的开根
scanf("%d%d%d%d",&l,&r,&a0,&n);
a[l] += a0*a0;
a[l + 1] += 2*a0 + 1 - 2*a0*a0;
a[l + 2] += a0*a0 -2*a0;
a[r + 1] += -(a0 + r - l)*(a0 + r - l) - 2*a0 - 2*(r - l);
a[r + 2] += 2*(a0 + r - l)*(a0 + r - l) + 2*a0 + 2*(r - l) - 1;
a[r + 3] += -(a0 + r - l)*(a0 + r - l);
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + a[i];
}
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + b[i];
}
for(int i = 1;i <= n;i ++){
b[i] = b[i - 1] + b[i];
}
2、二维差分
常数差分:
int a[N][N],b[N][N];
int xl,,yl,xr,yr,k,n;
scanf("%d%d%d%d%d%d",&xl,&xr,&yl,&yr,&k,&n);
a[xl][yl] += k;a[xr + 1][yr + 1] += k;
a[xl][yr + 1] -= k;a[xr + 1][yr] -= k;
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] + a[i][j] - b[i - 1][j - 1];
}
}