思路
其实一看到题目,大家就晓得了最简单的方法就是用多个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;
}
思路很简单,但是实话说,代码很容易写错。