21天零基础入门ACM
21天零基础入门ACM之 第1天
前缀和
什么是前缀和
前缀和,顾名思义,就是把前缀加起来。
加上给定一个数组a[] = {1,2,3,4,5},那么思考一下,它的前缀有哪些
{1},{1,2},{1,2,3},{1,2,3,4},{1,2,3,4,5}
前缀和就是他们前缀的和。
比如:
sum[0]=a[0];
sum[1]=a[0]+a[1];
sum[2]=a[0]+a[1]+a[2]
sum[3]=a[0]+a[1]+a[2]+a[3]
sum[4]=a[0]+a[1]+a[2]+a[3]+a[4]
sum数组就是a的前缀和数组
前缀和的作用
首先思考一下给出一个区间[l,r],如果我要计算 l 到 r 区间内所有元素的和,怎么做?
- 方法一:从区间 l 到 r 做一次循环,然后计数,时间复杂度位O(n);
- 方法二:利用前缀和,sum[r]-sum[l-1] 的值,即为区间 l 到 r的数字和的值,时间复杂度位O(1)
前缀和的应用
例题1:https://ac.nowcoder.com/acm/contest/11471/C
题目描述:
思路:妥妥的前缀和板子题,注意千万不要暴力模拟,时间复杂度为O(n*n),绝对超时。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
int n, m;
ll nums[N];
ll sum[N]; // 前缀和数组
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> nums[i];
sum[i] = sum[i - 1] + nums[i];
}
while (m--) {
int l, r;
cin >> l >> r;
cout << sum[r] - sum[l - 1] << endl; //利用前缀和快速输出区间和
}
return 0;
}
例题2:https://ac.nowcoder.com/acm/contest/19483/A
题目描述:
思路:还是前缀和,只不过sum数组存的是前缀积,求[l,r]的积的时候,只需要sum[r]/sum[l-1] 即可,但是此题要用上逆元,有兴趣的小伙伴可以去看看逆元。
代码:
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; }
ll qpow(ll a, ll b, ll mod) { ll ans = 1; a%=mod; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int mod=1e9+7;
const int N=1e5+7;
ll n, m, a[N];
int x, y;
int main() {
a[0] = 1;
while (cin >> n >> m) {
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 2; i <= n; i++) {
a[i] = (a[i - 1] * a[i]) % mod;
}
while (m--) {
cin >> x >> y;
cout << (qpow(a[x - 1], mod - 2, mod) * a[y]) % mod << endl;
// 逆元求出a[y] / a[x-1] 的积
}
}
return 0;
}