Hello!大家好,我是@学霸小羊,今天讲一下前缀和算法。
这要从一个故事说起。
一天,老师叫小明做一道题:一个长度为n的数组a,请你计算a[x]+a[x+1]+a[x+2]+ ···+a[y-1]+a[y]。
输入数据
第1行 1个整数n 0≤n≤1,000,000
第2行 2个整数x,y 0≤x,y≤n
第3行 n个整数 第 i 个整数是 a[ i ]
输出数据
1行 输出 a[x]+a[x+1]+a[x+2]+ ···+a[y-1]+a[y]
输入样例1
5
2 4
1 4 3 6 7
输出样例1
13
【选做】(大家可以自己做一下,也可以不做)
小明打代码有1年了,自然会打代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],x,y;
int main()
{cin>>n>>x>>y;for(int i=1;i<=n;i++){cin>>a[i];}int s=0;for(int i=x;i<=y;i++){s+=a[i];}cout<<s;return 0;
}
小明得意地抬起了头,因为他100分了,老师为了加大难度,让他做这题:一个长度为n的数组a,询问q次,每次输入x,y,计算a[x]+a[x+1]+a[x+2]+ ···+a[y-1]+a[y]。
输入数据
第1行 2个整数n,q 0≤n,q≤1,000,000
第2行 n个整数 第 i 个整数是 a[ i ]
第3~3+q行 每行2个整数x,y 0≤x,y≤n
输出数据
q行 每行输出询问的答案
小明打出了以下代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],x,y,q;
int main()
{cin>>n>>q;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=q;i++){int s=0;cin>>x>>y;for(int j=x;j<=y;j++){s+=a[j];}cout<<s<<endl;}return 0;
}
这次,小明没能全对,有几个样例超时了。
老师见了,叫他不要骄傲,给他讲了前缀和算法:
前缀和数组的每一项是可以通过原序列以递推的方式推出来的,递推公式就是:s[i]=s[i-1]+a[i]。
这与递推算法有关,没学过的先去学一学:
【算法】递推&递归https://blog.csdn.net/yangyanbin_sam/article/details/139182393?spm=1001.2014.3001.5501前缀和可以不超时,那么就可以用来做这题。
(分析一下时间复杂度,用小明原来的方法,最好的情况是O(q),最坏的情况是O(n*q),1,000,000*1,000,000,肯定超时)
用前缀和数组求第x项和第y项之间包括(第x项和第y项,y>x)的公式:s[y]-s[x-1]
听完老师的讲解后,小明打出了正确代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],s[1000005],x,y,q;
int main()
{cin>>n>>q;for(int i=1;i<=n;i++){cin>>a[i];s[i]=s[i-1]+a[i];}for(int i=1;i<=q;i++){cin>>x>>y;cout<<s[y]-s[x-1]<<endl;}return 0;
}
你学会前缀和算法了吗?今天就讲到这里,拜拜!