前缀和
顾名思义:前n项和。
一般情况下,如果给出一串长度为n的a1,a2,a3…an,再给出m个询问,每次询问给出L,R两个数,要求给出区间[L,R]里的数的和。如果暴力的话,肯定会超时。但我们如果去用前缀和去计算的话(先分别求出前i项和,后面求a[R]-a[L-1]就可以得到我们要求的答案了),时间复杂度会降到O(n+m)。
差分
首先,给出一个问题:
给出n个数,再给出Q个询问,每个询问给出le,ri,x,要求你在le到ri上每一个值都加上x,而只给你O(n)的时间范围,怎么办?
思考一下:
如果暴力,卡一下le和ri,随随便便让你O(n^2)T成狗。
用线段树或树状数组搞一搞,抱歉,这个复杂度是O(Qlogn)的,还是会T(虽然他们解决别的题目很NB)
差分,没错,就是标题,很高兴O(n)+常数…(思想:在询问中我们不去for来加x,而是做一个标记,最后一起加上。)
实现方法:
先另外开一个专门差分的数组(大小=题中的序列长度
假如在3~8的区间上加上5,那我们在差分数组中的3位置上加上一个5(原因暂时不懂没关系,用笔先跟着模拟),再在8+1的位置上减一个5,如此操作完Q次。
假如我们只有这一次操作,开始统计答案,运用前置和的思想,那么你会发现(如果你模拟了的话),在3~8的区间上,你已经使差分数组全部加上了5(推广到所有Q一起统计答案依旧正确)
再用O(n)的for把他们加到原序列之中去,输出!
看一下复杂度,果然:O(常数*n).
代码实现:
#include <stdio.h>
int main()
{
int num[100]={0};
int chafen[100]={0};
int i=1,q,le,ri,x,j,add=0,a,b;
while(scanf("%d",&num[i])!=EOF)
{
i++;
}
printf("请输入进行几次操作:");
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d",&le,&ri,&x);
chafen[le]+=x;
chafen[ri+1]-=x;
}
for(j=1;j<i;j++)
{
add+=chafen[j];
num[j]+=num[j-1]+add;
}
printf("请输入查询区间的和:");
scanf("%d%d",&a,&b);
printf("%d",num[b]-num[a-1]);
return 0;
}