前缀和、差分(某个区间加一次函数、二次函数)

前缀和、差分区间

有一个这样的问题:给你一串长度为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
题解

好了差不多讲这么多了,希望对你有好处,当然有错误也请各路神犇指出。
如有不懂的请下方留言。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值