蓝桥杯抱佛脚第二天|简单枚举,前缀和

题单:https://www.luogu.com.cn/training/743042

状态:前缀和确实好用,要掌握,多多思考一下肯定可以的

B3612 【深进1.例1】求区间和

题目链接:B3612 【深进1.例1】求区间和 - 洛谷

题目描述

给定 n 个正整数组成的数列 a 1,a 2,⋯,a**nm 个区间 [l**i ,r**i ],分别求这 m 个区间的区间和。

输入格式

第一行包含一个正整数 n,表示序列的长度。

第二行包含 n 个正整数 a 1,a 2,⋯,a**n

第三行包含一个正整数 m,表示区间的数量。

接下来 m 行,每行包含两个正整数 l**i ,r**i ,满足 1≤l**ir**in

输出格式

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 - 洛谷

题目描述

给定一个 nm 列的矩阵 a ,有 q 次询问,每次给定 (u ,v ) 和 (x ,y),请你求出:

(i =ux**j =vyai ,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≤uxn ,1≤vym

数据保证 ∑(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;
}
相关推荐
2301_793804692 小时前
C++安全编程指南
开发语言·c++·算法
2301_800895102 小时前
2024蓝桥杯B组初赛--备战蓝桥杯版h
蓝桥杯
m0_518019482 小时前
分布式系统安全通信
开发语言·c++·算法
AC__dream2 小时前
2024秋招-字节跳动-算法岗笔试
数据结构·算法
一叶落4382 小时前
LeetCode 151. 反转字符串中的单词(C语言)【双指针 + 字符串处理】
c语言·数据结构·算法·leetcode
_olone2 小时前
牛客每日一题:刷题统计(Java)
java·算法·容斥原理·牛客
无敌憨憨大王2 小时前
DFS(深搜)
算法·深度优先·图论
junnhwan2 小时前
LeetCode Hot 100——栈
java·数据结构·算法·leetcode·hot 100
sqyno1sky2 小时前
代码动态生成技术
开发语言·c++·算法