202104-2【邻域均值】

思路

其实一看到题目,大家就晓得了最简单的方法就是用多个for,每次重复求和即可,但是不用想,肯定是70分。
我看到这道题的首要想法就是肯定要利用上一个求和的值,因为每次求和有很多重复的计算,我先讲讲我的思路
其实求和也就是向右移动和向下移动。
例如,r=1,数据如下:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
(1)向右移动:变化的是i,不变的是j,详解如下:
初始为: 右移1格后:
01 | 012
45 | 456
在初始的基础上要进行的操作是:要用新增的第3列减去第0列,再加上初值的所有值。(即新增的值加上左边一格sum【i】【j-1】的值。)
up和down用来计算新增列对应的各行,在这即1,2行(对应变化的i)
ri和le用来表示新增的列,在这即第0和3列(对应不变的j)
最后用这格的总和除以领域的格子总数。
代码如下:

if(j!=1)//右
            {
                int up=max(i-r,0);int down=min(i+r,n+1);int ri=min(j+r,n+1);int le=max(j-r-1,0);
                for(int yi=up;yi<=down;yi++)sum[i][j]=sum[i][j]+c[yi][ri]-c[yi][le];
                sum[i][j]+=sum[i][j-1];
                if((sum[i][j]*1.0)/((ldown-lup+1)*(lri-lle+1))<=t )cnt++;
            }

(2)向下移动:变化的是j,不变的是i,详解如下:
初始为:
01
45
下移1格后:
01
45
89
在初始的基础上要进行的操作是:要用新增的第3行减去第0行,再加上初值的所有值。(即新增的值加上上边一格sum【i-1】【j】的值。)
up和down用来计算新增行对应的各列,在这即1,2列(对应变化的j)
ri和le用来表示新增的行,在这即第0和3行(对应不变的i)
最后用这格的总和除以领域的格子总数。
代码如下:

if(j==1)//下
            {
                int le=max(j-r,0);int ri=min(j+r,n+1);int down=min(i+r,n+1);int up=max(i-r-1,0);
                for(int yi=le;yi<=ri;yi++)sum[i][j]=sum[i][j]+c[down][yi]-c[up][yi];
                sum[i][j]+=sum[i-1][j];
                if((sum[i][j]*1.0)/((ldown-lup+1)*(lri-lle+1))<=t )cnt++;
            }

注意事项

上面向右或者向下是基于有了基础的部分值来说的,具体来说就是在进行上面的步骤时,我们已经计算了c矩阵中r*(r+1)的值后才开始用的。即初始时sum【1】【1】已经加上了c矩阵中r*(r+1)的值
代码如下:

 if(i==1&&j==1)//计算sum[1][1]-(r+1)那一行的值
            {
                int ri=min(n,1+r);
                int down=min(n,r);
                for(int x=1;x<=down;x++)
                {
                    for(int y=1;y<=ri;y++)
                    sum[1][1]+=c[x][y];
                }
            }

说明下原因:因为每当j=1时,咱就要向下移动了,之后j>1之后,就是向右移动。由于初始时,j=1就要向下移动1,因此在计算最初的sum【1】【1】时,是计算c矩阵中r*(r+1)的值。

100分完整代码

#include <iostream>
using namespace std;
#include <bits/stdc++.h>
#include<algorithm>
int c[602][602];
int sum[602][602];
int main()
{
    int n,l,r,t;
    int cnt=0;
    cin>>n>>l>>r>>t;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){cin>>c[i][j];}

    for(int i=1;i<=n;i++)//向下移动;
    {
        int lup = (i-r<1) ? 1 : (i-r);
		int ldown = (i+r>n) ? n : (i+r);
        for(int j=1;j<=n;j++)//向右移动
        {
            int lri = (j+r>n) ? n : (j+r);
			int lle = (j-r<1) ? 1 : (j-r);
            if(i==1&&j==1)//计算sum[1][1]-(r+1)那一行的值
            {
                int ri=min(n,1+r);
                int down=min(n,r);
                for(int x=1;x<=down;x++)
                {
                    for(int y=1;y<=ri;y++)
                    sum[1][1]+=c[x][y];
                }
            }
            if(j==1)//下
            {
                int le=max(j-r,0);int ri=min(j+r,n+1);int down=min(i+r,n+1);int up=max(i-r-1,0);
                for(int yi=le;yi<=ri;yi++)sum[i][j]=sum[i][j]+c[down][yi]-c[up][yi];
                sum[i][j]+=sum[i-1][j];
                if((sum[i][j]*1.0)/((ldown-lup+1)*(lri-lle+1))<=t )cnt++;
            }
            if(j!=1)//右
            {
                int up=max(i-r,0);int down=min(i+r,n+1);int ri=min(j+r,n+1);int le=max(j-r-1,0);
                for(int yi=up;yi<=down;yi++)sum[i][j]=sum[i][j]+c[yi][ri]-c[yi][le];
                sum[i][j]+=sum[i][j-1];
                if((sum[i][j]*1.0)/((ldown-lup+1)*(lri-lle+1))<=t )cnt++;
            }

        }
    }
    cout<<cnt;
    return 0;
}

思路很简单,但是实话说,代码很容易写错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值