作者:小妮无语
专栏:暑假基础集训营🚶♀️✌️道阻且长,不要放弃✌️🏃♀️
目录
一维前缀和
二维前缀和
例题1:最大子矩阵
例题2: 激光炸弹
一维前缀和
本题唯一要注意的是数据范围!!!
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,q;
long long a[N];
// long long f[N];
//观察数据范围1e9,最多1e5个数据如果做累加肯定是爆int(1e9),所以开longlong
int main()
{
cin>>n>>q;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]+=a[i-1];
//由于a[i-1],在a[i],之前都已经被更新过了,
//因为a[i],在以后也不会用到只是用来记录做累加用的,
//直接在它上面累加一个道理,可以直接覆盖
// f[i]=f[i-1]+a[i];
}
while(q--)
{
int l,r;
cin>>l>>r;
cout<<a[r]-a[l-1]<<endl;
}
return 0;
}
二维前缀和
例题1:最大子矩阵
原题链接
Problem Description
给你一个m×n的整数矩阵,在上面找一个x×y的子矩阵,使子矩阵中所有元素的和最大。
Input
输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为四个正整数m,n,x,y(0<m,n<1000 AND 0<x<=m AND 0<y<=n),表示给定的矩形有m行n列。接下来这个矩阵,有m行,每行有n个不大于1000的正整数。
Output
对于每组数据,输出一个整数,表示子矩阵的最大和。
Sample Input
1 4 5 2 2
3 361 649 676 588
992 762 156 993 169
662 34 638 89 543
525 165 254 809 280
Sample Output
2474
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m,t,x,y;
int f[N][N];
int main()
{
cin>>t>>n>>m>>x>>y;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>f[i][j];
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
//这个和一维前缀和原理一样上面解释过了
}
int cnt=-1;//求最大定义最小,求最小定义最大
for(int i=x;i<=n;i++)
{
for(int j=y;j<=m;j++)
{
cnt=max(cnt,f[i][j]-f[i-x][j]-f[i][j-y]+f[i-x][j-y]);
//这里为啥不是i-x-1?以为这是边界当i=3,r=2时你想要的是2-3区间内的元素的和,而正好i-r=1,减去的正好就是你区间前的呢个数
//这i定义的x,其实就已经默认了下标是从1开始的了
}
}
cout<<cnt;
return 0;
}
例题2: 激光炸弹
题目
地图上有 N个目标,用整数 Xi,Yi表示目标在地图上的位置,每个目标都有一个价值 Wi。
注意:不同目标可能在同一位置。
现在有一种新型的激光炸弹,可以摧毁一个包含 R×R个位置的正方形内的所有目标。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 x,y轴平行。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N和 R,分别代表地图上的目标数目和正方形包含的横纵位置数量,数据用空格隔开。
接下来 N行,每行输入一组数据,每组数据包括三个整数 Xi,Yi,Wi,分别代表目标的 x 坐标,y 坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0≤R≤10^9
0<N≤10000
0≤Xi,Yi≤5000
0≤Wi≤1000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1
本题难点
1.数据范围
2.下标题目是从0开始给的,前缀和唯一点下标必须从1开始,所以开始要注意加1
3.一点细节上的处理,思路和上一题一样
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int n,r;
int f[N][N];
int main()
{
cin>>n>>r;
while(n--)
{
int b,c,d;
cin>>b>>c>>d;
// scanf("%d%d%d",&b,&c,&d);
// f[b++][c++]+=d;//这个地方写错了,太愚蠢了,b++,是先用b,用完再++,呢加的意义是啥
f[b+1][c+1]+=d;//为了下标从1开始,所有的元素都往后移动,这里由于题目说可能会有重复出现,所以要进行累加
}
for(int i=1;i<=5001;i++)
{
for(int j=1;j<=5001;j++)
f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+f[i][j];
}
if(r>=5000) //如果r本身就大于咱们的地的大小呢么全炸便是最大的范围,直接特判输出
{
cout<<f[5001][5001];//要加一,因为所有都得是加一存的
return 0;//在一个函数中只要遇到return呢么这个函数就结束,这结束的是main函数
}
int cnt=-1;
for(int i=r;i<=5001;i++)
{
for(int j=r;j<=5001;j++)
{
cnt=max(cnt,f[i][j]-f[i-r][j]-f[i][j-r]+f[i-r][j-r]);//同上一题,一模一样
}
}
cout<<cnt;
return 0;
}
第一周例题over!!!
== 欢迎来到暑假基础集训营的小菜鸟频道,睡不着就看看吧!==
== 跟着小张刷题吧!==