鉴于写完两年6道题的第二题后发现前缀和用的比较多,今天刷洛谷的前缀和基础算法
[【算法2-1】前缀和、差分与离散化 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)](https://www.luogu.com.cn/training/200#problems)
### Day7:1.# P8218 【深进1.例1】求区间和 2.# P1719 最大加权矩形 3.202104-2
#### 1.# P8218 【深进1.例1】求区间和(一维前缀和)
(1)题目索引由1开始,为了方便直观,采用s[i]=s[i-1]+a[i],sum[l.r]=s[r]-s[l-1]
(2)代码:
```
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
vector<int> va(n+1,0);
vector<int> vsum(n+1,0);
for(int i=1;i<=n;i++){
scanf("%d",&va[i]);
}
for(int i=1;i<=n;i++){
vsum[i]=vsum[i-1]+va[i];
}
int m,l,r;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d%d",&l,&r);
int res=vsum[r]-vsum[l-1];
printf("%d\n",res);
}
return 0;
}
```
#### 2.# P1719 最大加权矩形(二维前缀和)
(1)题目要求最大矩形(子矩阵)的和,即x1,y1,x2,y2是要自己寻找的,此题n较小,可以遍历
(2)代码:
```
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
vector<vector<int>> va(n+1,vector<int>(n+1,0));
vector<vector<int>> vs(n+1,vector<int>(n+1,0));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&va[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
vs[i][j]=vs[i-1][j]+vs[i][j-1]-vs[i-1][j-1]+va[i][j];
}
}
int max=numeric_limits<int>::min();
for(int x1=1;x1<=n;x1++){
for(int y1=1;y1<=n;y1++){
for(int x2=x1;x2<=n;x2++){
for(int y2=y1;y2<=n;y2++){
int sum=vs[x2][y2]-vs[x2][y1-1]-vs[x1-1][y2]+vs[x1-1][y1-1];
if(sum>max){
max=sum;
}
}
}
}
}
printf("%d",max);
return 0;
}
```
#### 3.202104-2:邻域均值(二维前缀和)
(1)题目:
题目要求就是求二维数组一个方框内的元素和,并除以个数求平均值与阈值t比较,就想到二维前缀和优化,**注意**:邻域:对于矩阵内每一个点A [i] [j]来说,其邻域内的点A[x] [y]满足:0 ≤ x , y < n 且 且∣x−i∣≤r且∣y−j∣≤r,其中r为输入的一个正整数,题目是[0,n),但是我们二维前缀和一般为[1,n]注意区别
(2)代码(100):
```
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,L,r,t;
scanf("%d%d%d%d",&n,&L,&r,&t);
vector<vector<int>> va(n+1,vector<int>(n+1,0));
vector<vector<int>> vs(n+1,vector<int>(n+1,0));
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&va[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
vs[i][j]=vs[i-1][j]+vs[i][j-1]-vs[i-1][j-1]+va[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int x1=max(1,i-r);//注意和1比
int y1=max(1,j-r);
int x2=min(n,i+r);//注意和n比
int y2=min(n,j+r);
int cnt=(x2-x1+1)*(y2-y1+1);
long long sum=vs[x2][y2]-vs[x2][y1-1]-vs[x1-1][y2]+vs[x1-1][y1-1];
if(sum<=static_cast<long long>(cnt*t)){
res++;
}
}
}
printf("%d",res);
return 0;
}
```
(3)优化:
1.输入数据量较大时,使用`ios::sync_with_stdio(false)`来加快输入输出,并使用`cin`和`cout`,可能比scanf和printf更快,但此时两者不能交叉使用
2.不要计算乘法`long long`,一有可能溢出,二大数计算太慢,改为除法,记得转换类型
```
double tmp=(double)sum/(double)cnt;
if(tmp<=t){
res++;
}
```