前缀和、差分区间
有一个这样的问题:给你一串长度为n的数列a1,a2,a3…an,再给你多个区间[L,n],让你在这个区间上a数组所有数都加上x(x为L与当前位置的间隔+1),假设L=1,则a[1]就要加1,a[2]就要加2,以此类推。当然求解这个方法最直接的就是暴力,每次区间都遍历一次。很显然数据大的时候直接超时。
如果让区间进行加减某个常数,这就是我们前缀和、差分模板了。
代码
const int man = 1e5+10;
int a[man],l,r;
for(int i = 1;i <= m;i++){cin >> l >> r; a[l]++,a[r+1]--;}
for(int i = 1;i <= n;i++)a[i] += a[i-1];
对于上述的问题,我们也可以用前缀和、差分来完成。
修改区间[L, n]的值,让其加上x,我们可以把x看做当前位置与L的距离加上1(L=1,pos = 2,dis =2-1,x = dis+1),这样的话让[L, n]这个区间加上x就可以直接用2次前缀和就可以解决了。先让a[L]++;然后在求2次前缀和就得到最终的答案了。第一次前缀和让每个值都加了一个1,然后第二次前缀和就让每个值加了个pos与L的距离,这样2次前缀和下来就得到答案了。
代码
void get(int *a,int n){
for(int i = 1;i <= n;i++){
a[i] += a[i-1];
}
}
int main(){
for(int i = 1;i <= m;i++){
cin >> pos;
a[pos]++;
}
get(a);//第一次让每个值都加上1
get(a);//第二次让每个值加上与L的距离
return 0;
}
那我们在把这个问题扩展成在区间[L, n]加上ax+b呢,又该怎样做呢.如果你对上面的理解比较深刻,相信对这个也会一眼看出。
首先对于加上ax,那就是在x的基础上乘以一个a,那么我们a[pos]++这里就要修改为 a[pos] += a;然后ax+b,这个b就是在我们进行最后一次前缀和之前在进行一次差分,让之前每个L的位置a[L]+b,最后一个前缀和就出来了。
代码
void get(int *a,int n){
for(int i = 1;i <= n;i++){
a[i] += a[i-1];
}
}
int POS[MAN];
int main(){
int cnt = 0;
for(int i = 1;i <= m;i++){
cin >> pos;
POS[cnt++] = pos;
a[pos] += A;//假设A已给出
}
get(a);//第一次让每个值都加上A
for(int i = 0;i < cnt;i++){
a[POS[i]]+= B;//假设B已给出
}
get(a);//第二次让每个值加上与L的距离
return 0;
}
对于让区间[L,n]加上ax+b这样的一次函数问题,我们已经可以o(m+n)完美的解决了,那么问题又来了,对于区间[L,n]加上二次函数ax2+bx+c这样的式子时,我们又应该怎么处理呢,接下来讲解加上x2的情况。
首先我们知道前缀和就是求当前位置之前的所有数的和,就是sn,然后我们认为a数组的初始值全部为0,我们让a[1]加1,然后求2遍前缀和,这样得到x,然后在对x进行求前缀和,得到sn = (1+x)*x/2这样一个公式,化简之后sn = 1/2x2 + 1/2x,而我们要得到的是x2,所以我们可以让sn 加上1/2x2 - 1/2x,最后就可以得到x2,总的话就要进行3次前缀和。
代码
void get(int *a,int n){
for(int i = 1;i <= n;i++){
a[i] += a[i-1];
}
}
int main(){
for(int i = 1;i < =m;i++){
int pos;cin >>pos;
a[pos]++;//当前位置加一很容易理解。
a[pos+1]++;//这里可能会比较难懂,pos+1这个位置加上1,就是pos对于n的相对位置是x,而pos+1对于n的相对位置就是x-1
}
get(a,n);
get(a,n);//前2个就是得到x。
get(a,n);//对x进行求前缀和,得到sn.
return 0;
}
对==a[pos+1]++;==这个为什么要pos+1这里加1,就是让sn加上1/2x2 - 1/2x,
我们pos 这个位置对于n是相对于x个距离,然后pos+1这个位置对于n是相对于x-1个距离。
对于ax2+bx+c二次函数跟上面的ax+b做法相同,读者有兴趣可以试着实现。
下面给个例题:
小w的糖果
题意:
有三种操作:
1.从当前pos开始每个位置加1。
2.从当前pos开始每个位置加x。
3.从当前pos开始每个位置加x2。
题解
好了差不多讲这么多了,希望对你有好处,当然有错误也请各路神犇指出。
如有不懂的请下方留言。