题单:https://www.luogu.com.cn/training/743042
状态:前缀和确实好用,要掌握,多多思考一下肯定可以的
B3612 【深进1.例1】求区间和
题目描述
给定 n 个正整数组成的数列 a 1,a 2,⋯,a**n 和 m 个区间 [l**i ,r**i ],分别求这 m 个区间的区间和。
输入格式
第一行包含一个正整数 n,表示序列的长度。
第二行包含 n 个正整数 a 1,a 2,⋯,a**n。
第三行包含一个正整数 m,表示区间的数量。
接下来 m 行,每行包含两个正整数 l**i ,r**i ,满足 1≤l**i ≤r**i ≤n。
输出格式
共 m 行,其中第 i 行包含一个正整数,表示第 i 组答案的询问。
输入输出样例
输入
4
4 3 2 1
2
1 4
2 3
输出
10
5
说明/提示
样例解释
第 1 到第 4 个数加起来和为 10。第 2 个数到第 3 个数加起来和为 5。
数据范围
对于 50% 的数据:n ,m≤1000;
对于 100% 的数据:1≤n ,m ≤105,1≤a**i≤104。
看到这道题的第一个想法当然又是暴力了,写层for循环计算所要区间的和,果不其然又又又超时了,嗯......这道题用前缀和来解决就会简单而高效。
//暴力,只过了40%
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n,m,a,b,sum=0;
cin>>n;
vector<int> value(n);
for(int i=0;i<n;i++){
cin>>value[i];
}
cin>>m;
while(m--){
cin>>a>>b;
sum=0;
for(int j=a-1;j<=b-1;j++){
sum+=value[j];
}
cout<<sum<<endl;
}
return 0;
}
把1到r的价值总和算出存入prefix中,如果题目要l到r的,那么就prefix[r]-prefix[l-1]就是最后的结果,就不用在从头开始累加。
//前缀和
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> value(n);
vector<long long> prefix(n + 1, 0); // prefix[0] = 0
for (int i = 0; i < n; i++) {
cin >> value[i];
prefix[i + 1] = prefix[i] + value[i]; // 前缀和
}
int m;
cin >> m;
while (m--) {
int l, r;
cin >> l >> r;
// 区间 [l, r] 的和
cout << prefix[r] - prefix[l - 1] << '\n';
}
return 0;
}
B3693 数列前缀和 4
题目链接:B3693 数列前缀和 4 - 洛谷
题目描述
给定一个 n 行 m 列的矩阵 a ,有 q 次询问,每次给定 (u ,v ) 和 (x ,y),请你求出:
(i =u ∑x**j =v ∑yai ,j)mod264
也就是求出以 (u ,v ) 为左上角、(x ,y) 为右下角的矩形元素和对 264 取余数的结果。
输入格式
本题单测试点内有多组测试数据。
输入的第一行是一个整数 T,表示数据组数。接下来依次给出每组数据的输入信息:
第一行三个整数,依次表示矩阵的行数 n 和列数 m 以及询问数 q 。 接下来 n 行,每行 m 个整数。第 i 行第 j 个整数表示 a**i ,j 。 接下来 q 行,每行四个整数,依次为 u ,v ,x ,y,表示一组询问。
输出格式
为了避免输出过大,对于每组数据,请输出一行一个整数,表示本组数据的所有询问的答案的按位异或和。
输入输出样例
输入
2
3 3 3
1 2 3
4 5 6
7 8 9
1 1 3 3
2 1 2 2
1 2 2 3
2 2 1
1 3
4 6
2 2 2 2
输出
52
6
说明/提示
样例 1 解释
对第一组数据,三次询问的答案依次为 45,9,16。其按位异或和为 52。
数据规模与约定
对全部的测试点,保证 1≤T ≤10,1≤n ,m ≤103,1≤q ≤106,0≤a**i <264,1≤u ≤x ≤n ,1≤v ≤y ≤m。
数据保证 ∑(n ×m )≤106,∑q≤106。即输入矩阵的总大小和询问总数均不超过 106。
这道题用暴力的话就会非常非常难,哈哈哈根本过不去测试。要选择采用前缀和,上一个题是一维前缀和,这个题是二维前缀和,可以画图理解一下。
#include<bits/stdc++.h>
using namespace std;
unsigned long long sum[2050][2050],temp,n,m,q,ans;
unsigned long long u,v,x,y;
signed main()
{
int t;
cin>>t;
while(t--)
{
ans=0; //记得每一次测试都要清空
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>temp;
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+temp;
}//二维前缀和
for(int i=1;i<=q;i++)
{
cin>>u>>v>>x>>y;
ans^=sum[x][y]+sum[u-1][v-1]-sum[u-1][y]-sum[x][v-1];// O(1)查询
}//异或处理答案,不取模是因为 unsigned long long 会自然溢出
cout<<ans<<endl; //记得换行
}
return 0;
}
P3131 [USACO16JAN] Subsequences Summing to Sevens S
题目描述
Farmer John 的 N 头奶牛站成一排,这是它们时不时会做的事情。每头奶牛都有一个独特的整数 ID 编号,以便 Farmer John 能够区分它们。Farmer John 希望为一组连续的奶牛拍照,但由于童年时与数字 1...6 相关的创伤事件,他只希望拍摄一组奶牛,如果它们的 ID 加起来是 7 的倍数。
请帮助 Farmer John 确定他可以拍摄的最大奶牛组的大小。
输入格式
输入的第一行包含 N (1≤N ≤50,000)。接下来的 N 行每行包含一头奶牛的整数 ID(所有 ID 都在 0...1,000,000 范围内)。
输出格式
请输出 ID 之和为 7 的倍数的最大连续奶牛组中的奶牛数量。如果不存在这样的组,则输出 0。
输入输出样例
输入
7
3
5
1
6
2
14
10
输出
5
说明/提示
在这个例子中,5+1+6+2+14=28。
这道题也是前缀和的应用,我的想法就是计算出前缀和,然后记录每个余数第一次出现的位置和最后一次出现的位置,然后找最大次数即可。本来是(prefix[j] - prefix[i]) % 7 == 0,那么 prefix[j] % 7 == prefix[i] % 7,所以问题转化为:找到最远的两个位置,它们的前缀和模7相等。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> prefix(n + 1, 0); // prefix[0] = 0
// 构建前缀和
for (int i = 1; i <= n; i++) {
long long temp;
cin >> temp;
prefix[i] = prefix[i-1] + temp;
}
// 记录每个余数第一次出现的位置和最后一次出现的位置
vector<int> first(7, -1); // 余数0-6,初始化为-1
vector<int> last(7, -1);
// 遍历所有前缀和(包括prefix[0])
for (int i = 0; i <= n; i++) {
int mod = prefix[i] % 7;
if (first[mod] == -1) {
first[mod] = i; // 记录第一次出现的位置
}
last[mod] = i; // 不断更新最后一次出现的位置
}
// 找最大距离
int maxLen = 0;
for (int r = 0; r < 7; r++) {
if (first[r] != -1) {
// 相同余数的第一次和最后一次之间的距离
maxLen = max(maxLen, last[r] - first[r]);
}
}
cout << maxLen << endl;
return 0;
}