首页 > 编程语言 >一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)

一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)

时间:2023-04-21 12:08:43浏览次数:46  
标签:前缀 nums int sum c++ 蓝桥 二维 数组 例题


文章目录

  • 前缀和
  • 二维前缀和
  • 总结
  • 3956. 截断数组
  • 99. 激光炸弹


前缀和

前缀和是一种常见的算法,用于快速计算数组中某一段区间的和。前缀和的思想就是预处理出数组中前缀和,然后用后缀和减去前缀和,即可快速计算区间和。

以一维数组为例,设 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++ 表示数组中第 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_02 个元素的值,一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_算法_03 表示数组中前 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_02 个元素的和,即: 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_数组_05 则对于区间 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_数组_06 的和可以表示为: 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_数组_07 这里需要注意的是,我们需要在原数组的前面插入一个值为 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_数组_08 的元素,这样才能计算出 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_前缀和_09,也就是前 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_数组_08

vector<int> a; // 原数组
vector<int> sum(a.size() + 1, 0); // 前缀和数组
// 计算前缀和
for (int i = 1; i <= a.size(); i++) {
    sum[i] = sum[i-1] + a[i-1];
}
// 计算区间和
int l = 3, r = 7;
int ans = sum[r] - sum[l-1]; //[3,7]的区间和

二维前缀和

对于二维数组,我们可以先对每一行进行一维前缀和,然后对每一列进行一维前缀和,即可得到二维前缀和数组。 设 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_蓝桥杯_11 表示二维数组中第 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_02 行第 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_前缀和_13 列的元素值,一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_14 表示以 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_15 为右下角的矩阵的元素和,则有: 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_算法_16 则对于矩阵 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_前缀和_17 的元素和可以表示为: 一维与二维前缀和(蓝桥杯复习+例题讲解+模板c++)_c++_18

vector<vector<int>> a; // 原数组
vector<vector<int>> sum(a.size() + 1, vector<int>(a[0].size() + 1, 0)); // 二维前缀和数组
//前缀和的预处理
for (int i=1;i<=a.size();i++){
    for (int j=1;j<=a[0].size();j++){
        sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    }
}
// 计算矩阵的元素和
int x1 = 2, y1 = 3, x2 = 5, y2 = 7;
int ans = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];

总结

前缀和是一种非常实用的算法,可以用于快速计算数组中某一段区间的和。在一维数组中,只需要预处理出前缀和数组即可;在二维数组中,需要先对每一行进行一维前缀和,然后再对每一列进行一维前缀和,得到二维前缀和数组。

3956. 截断数组

3956. 截断数组

题目要求:把一个数组从中间分开两份,使得这个数组被分成三份,其中每一份都是非空的,而且要求每一份的元素的和都相等。

例:

4
1 2 3 3

从下标为2的地方分第一份,下标为3的地方分第二份,因此可以分成如下的三段序列:

1 2,  3 ,  3

其中每一段的和都是相等的,为3。

每一段必须是非空的,如果:

2
0 0

则无解,因为这个序列无法分成三份,因此输出 0

同理,如果分不出三份,使得每一份的和都相等,则也输出0

我们需要得到的是分割的方案数。


一维前缀和的思想:我们统计这个序列的前缀和,以 1 2 3 3为例:

原数组为 nums[4]={1,2,3,3} ;前缀和数组为:presum[4]={1,3,6,9}

因此我们可以发现:如果数组的总和不能被3整除,则它一定不能分成三份,此时直接输出0即可。

如果数组的总和能够被3整除,则还不一定存在方案,例如:3 3,但是它只有两份。

我们可以得出另一个结论,如果数组总和能够被3整除,并且还必须需要分成三份。

因此我们可以计算出 avg=总和的三分之一,则我们必须满足两个临界点:

  1. 找到一个满足 avg*2 的地方,如果找到了这个地方为i, 则后面 i到n 的和一定是avg。
  2. 找到一个满足 avg 的地方,如果找到了这个地方,则我们统计满足这个地方的方案数。

最后如果在 avg*2 的地方加上 avg*1 的方案数,则就是整个数组分成三份的合法方案数,因为后面的avg*3的地方就是整个数组的和,找到了这两个地方就可以确定整个数组一定是合法的。


#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
const int N=1e5+10;
int nums[N],presum[N];
int n;
signed main(){
    cin>>n;
    int sum=0;
    for (int i=1;i<=n;i++){
        cin>>nums[i];
        presum[i]=nums[i]+presum[i-1];
        sum+=nums[i];
    }
    if (sum%3!=0){
        //一定不能分成三份
        cout<<0;
    }
    else{
        int avg=sum/3;
        int js=0;
        int ans=0;
        for (int i=1;i<n;i++){
            //一定要留给第三份一个元素的空间,所以不能取到n
            if (presum[i]==avg*2){
                ans+=js;
            }
            if (presum[i]==avg){
                ++js;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

99. 激光炸弹

99. 激光炸弹 - AcWing题库

题目要求:给你一个矩形区域,这个矩形区域上有几个点,每个点都具有一个值,并且给你一个R,使你在这个矩阵中所有的R*R的正方形中找到具有的值最大的一个正方形的总价值。

这道题就是二维前缀和的应用。

假设我的初始矩阵区域如图所示:

1 0
0 1

则转换为二维前缀和矩阵:

1 1
1 2

如果此时R为1,则表面上我们可以取得 2为最大值,但是其实我们的二维前缀和应该这样计算:

val=sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i][j]

val=2-1-1+1=1,则答案为1,根据原二维数组我们也可知,答案为1


因此我们只需要预处理出二维数组的前缀和即可,然后根据所给的R,找到一个最大的区域,使得值最大,统计最大值即可。

需要注意的几个地方:

  1. 可能会出现相同的位置具有多个值,则把他们的值相加即可
  2. 由于没有告诉这个矩形范围是多大,因此每次我们直接枚举到题目要求的极大值即可,即5e3左右
  3. 从可以容纳的最小的 R*R的正方形范围开始,统计每一个R*R的值,然后统计最大值。
#include <iostream>
#include <algorithm>
using namespace std;
const int N=5010;
int nums[N+10][N+10];
int n,r;
int main(){
    cin>>n>>r;
    //r可能会出现一个大值:1e9,但是只需要到N即可
    r=min(r,N);
    for (int i=1;i<=n;i++){
        int x,y,w;
        cin>>x>>y>>w;
        nums[x+1][y+1]+=w;//可能出现相同的位置,值相加
    }
    //预处理前缀和
    for (int i=1;i<=N;i++){
        for (int j=1;j<=N;j++){
            nums[i][j]+=nums[i-1][j]+nums[i][j-1]-nums[i-1][j-1];
        }
    }
    //求出每一个R*R的正方形做具有的最大值
    int ans=0;
    for (int i=r;i<=N;i++){
        for (int j=r;j<=N;j++){
            ans=max(ans,nums[i][j]-nums[i-r][j]-nums[i][j-r]+nums[i-r][j-r]);
        }
    }
    cout<<ans;
    return 0;
}


标签:前缀,nums,int,sum,c++,蓝桥,二维,数组,例题
From: https://blog.51cto.com/u_15744744/6212408

相关文章

  • 单调队列(例题详解+模板cpp)
    有一类问题需要维护一段区间内的最大值或最小值,例如滑动窗口、区间最值等问题。一般情况下,我们可以使用线段树、ST表等数据结构来解决这类问题,但是这些数据结构的实现较为复杂,需要一定的时间和精力来学习和掌握。而单调队列则是一个简单而高效的数据结构,可以用来解决这类问题。基本......
  • Trie字典树(例题详解+模板cpp)
    字典树(Trie树)一:概念字典树是一种树形结构,用于存储一组字符串,支持快速的字符串查找和前缀匹配。字典树的本质是利用字符串之间的公共前缀,将具有相同前缀的字符串合并在一起,从而实现高效的字符串操作。数据结构字典树是一棵多叉树,每个节点包含若干个指向子节点的指针,每个节点代表一......
  • bfs与dfs详解(经典例题 + 模板c-代码)
    文章目录模板+解析dfsbfs1562.微博转发3502.不同路径数165.小猫爬山模板+解析DFS(深度优先搜索)和BFS(广度优先搜索)是图论中两个重要的算法。dfs其中DFS是一种用于遍历或搜索树或图的算法,BFS则是一种用于搜索或遍历树或图的算法。两种算法都有其自身的优点和缺点,应用于不同的场景中......
  • 并查集及其扩展(附例题与完整讲解cpp)
    文章目录基础并查集1.P1551亲戚2.P1536村村通种类并查集1.P1892[BOI2003]团伙2.P1525[NOIP2010提高组]关押罪犯3.P2024[NOI2001]食物链带权并查集基础并查集并查集就是用来维护一些元素之间的关系的集合。例如A的亲戚是B,则我们可以把A与B放到同一个集合中,表示AB属......
  • 树状数组解决逆序对问题c++
    前言在算法竞赛中,求逆序对是一个常见的问题。逆序对是指在一个数列中,如果存在,且,那么就是一个逆序对。例如,数列中的逆序对有,总共有树状数组树状数组(FenwickTree)是一种高效的数据结构,用于维护数列的前缀和。树状数组的主要优势在于可以快速对数列进行单点更新和区间查询,时间......
  • 二分查找例题与模板(蓝桥杯复习+例题讲解+模板c++)
    文章目录二分模板1460.我在哪?102.最佳牛围栏113.特殊排序二分模板本文所使用的二分模板都是确保最终答案落在[L,R]以内,循环以L==R结束,每次二分的中间值会使mid成为左右区间的二者之一。单调递增序列找大于等于x的最小的值:区间的划分[l,mid][mid+1,r]while(l<r){ intmid......
  • 第三章部分例题(6)
    例3-13值传递与引用传递的比较设计思路:通过函数对数值进行改变观察值传递与应用传递后原数值的变化代码:#include<iostream>#include<iomanip>usingnamespacestd;voidfiddle(intin1,int&in2){in1+=100;in2+=100;cout<<"Thevaluesare";cout<......
  • AC自动机的C++代码实现与过程讲解
    AC自动机(Aho-Corasickalgorithm)是一种多模式字符串匹配算法。它可以快速地查找多个模式串在一段文本串中出现的位置,并支持模式串的预处理,使得在查询时能够快速地匹配。C++代码实现:#include<iostream>#include<queue>#include<cstring>usingnamespacestd;constintM......
  • 网络流的C++代码实现与过程讲解
    网络流是一种非常重要的图论算法,它在许多实际问题中得到广泛应用。本文将介绍网络流算法的C++代码实现与过程讲解。算法概述网络流算法是通过将图中的边看作流量通道,将图的点看作流量的起点或终点,来求解图中的最大或最小流量的问题。它是一种非常重要的最优化算法,广泛应用于图论......
  • 初学者代码训练Day4(c/c++)
    题目:借书方案知多少小明有5本新书,要借给A、B、C这3位小朋友,若每人每次只能借1本,则可以有多少种不同的借法? 流程图  代码 #include<iostream>usingnamespacestd;intmain(){intA=0,B=0,C=0,sum=0;for(A=1;A<=5;A++){for(B=1;B<=5&&B!=A;B++)......