CCF-CSP认证考试准备第七天

鉴于写完两年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++;
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值