题目描述
🌙你站在桥上看风景,看风景的人在楼上看你。
明月装饰了你的窗子,你装饰了别人的梦。
蛋仔派对深受Bingbong喜爱,但是他玩游戏一向很菜,特别是在生存战中总落入下风,以下是某生存关的规则:
在万米高空有一个平行于地面且大小为n∗m的地图砖块,以俯视角度观看时,从上往下依次为第1~n行,从左往右依次为第1~m列,这个地图的特性是每个单位时间过后最外圈的砖块都会掉落,站在上面的蛋仔会因为踩空而摔落无尽的深渊,导致游戏失败。
形式上来说,若当前还未掉落砖块的总行数row≥3时,则当前的第1行和第row行的砖块会在下一个单位时间掉落,row减少2,否则row保持不变,列同理,可参考样例理解。
在0时刻总共有k只蛋仔位于此地图上,第i只蛋仔的坐标为(xi,yi),他们会以每个单位时间一格的速度向四个方向移动或者选择不移动,具体描述为如果当前在(x,y)(x,y)(x,y),那么下一个位置可以是(x−1,y),(x+1,y),(x,y−1),(x,y+1)(x-1,y),(x+1,y),(x,y-1),(x,y+1)(x−1,y),(x+1,y),(x,y−1),(x,y+1)或者(x,y)(x,y)(x,y),游戏胜利的标志为蛋仔移动到地图的中央,坐标为(n/2+1,m/2+1)(n/2+1,m/2+1)(n/2+1,m/2+1),保证n,mn,mn,m均为奇数。好奇的Bingbong想要知道这关共有多少个蛋仔通过此关,请您帮他计算一下。
注意:
1.一个位置允许多个蛋仔同时存在。
2.砖块掉落后对于地图中央参数的mn,m均为初始值,保持不变。
输入描述:
第一行包含3个整数n(1≤n<500),m(1≤m<500),k(1≤k≤n∗m) n(n<500),m(1<m<500),k(1<k<n*m) n(1≤n<500),m(1≤m<500),k(1≤k≤n∗m),表示地图的行列大小和蛋仔数量。 接下来k行,每行2个整数x,y,第i行的数表示第i只蛋仔位于地图上的坐标。
输出描述:
一个整数,表示最终通过的蛋仔数量。
示例1
输入
3 3 3 2 2 1 1 2 1
输出
2
说明
初始时刻蛋仔所处位置如下:
第一只蛋仔由于已经位于地图中央砖块,所以通过此关。
第二只无论向下还是向右移动都会因为最外圈红色部分的砖块掉落而摔入无尽的深渊,所以此只蛋仔游戏失败。
第三只蛋仔可以选择向右跳一步,通过此关。
示例2
输入
1 5 3 1 1 1 5 1 2
输出
3
说明
初始时刻蛋仔所处位置如下:
第一秒过后3只蛋仔位置和砖块掉落状态如图所示:
第二秒过后3只蛋仔位置和砖块掉落状态如图所示:
所以最终3只蛋仔全部通关。
直到比赛结束看到大佬的代码才发现是曼哈顿距离qwq
当时我还在仔仔细细的判断中心点延申的中线,附上代码看一眼蒟蒻是怎么思考题的,以及时间浪费在了哪里
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N=1e7+10;
int a[510][510];
signed main()
{
std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m,q;cin>>n>>m>>q;
int p=q;
int sum=0;
while(q--)
{
int x,y;cin>>x>>y;
a[x][y]++;
}
if(n==3&&m==3)
{
for(int i=1;i<=n;i++)
{
if(i==n/2+1)continue;
sum+=a[i][1];
sum+=a[i][m];
}
for(int i=2;i<=m-1;i++)
{
if(i==m/2+1)continue;
sum+=a[1][i];
sum+=a[n][i];
}
}
else
{
for(int i=1;i<=n;i++)
{
if(i==n/2+1)continue;
if(a[i][m/2+1]!=0)
sum+=a[i][m/2+1];
}
for(int i=2;i<=n-1;i++)
{
if(i==n/2+1)continue;
if(a[i][m/2]!=0)
sum+=a[i][m/2];
}
for(int i=2;i<=n-1;i++)
{
if(i==n/2+1)continue;
if(a[i][m/2+2]!=0)
sum+=a[i][m/2+2];
}
for(int i=1;i<=m;i++)
{
if(i==m/2+1)continue;
if(a[n/2+1][i]!=0)
sum+=a[n/2+1][i];
}
for(int i=2;i<=m-1;i++)
{
if(i==m/2+1||i==m/2||i==m/2+2)continue;
if(a[n/2][i]!=0)
sum+=a[n/2][i];
}
for(int i=2;i<=m-1;i++)
{
if(i==m/2+1||i==m/2||i==m/2+2)continue;
if(a[n/2+2][i]!=0)
sum+=a[n/2+2][i];
}
}
if(n==1||m==1)
{
cout<<p;
}
else
{
sum+=a[n/2+1][m/2+1];
cout<<sum;
}
return 0;
}
以上是错误题解
解题思路
我们发现地图是一层一层往内塌陷,所以当一个点在中点延申的中线时,一定可以逃生
或者当一个数的x轴+y轴距离终点的距离(曼哈顿距离)(一格一格走)小于从外层塌陷到终点的距离(即最外层到终点的距离)(这个距离为正所以带绝对值)
经过上述解释可以得出当这个点的曼哈顿距离<离终点的绝对值距离可以逃生
曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离正是在南北方向上旅行的距离加上在东西方向上旅行的距离,因此,曼哈顿距离又称为出租车距离。
代码实现
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n,m,k;cin>>n>>m>>k;
int xx=n/2+1,yy=m/2+1;//终点坐标
int sum=0;//计数
while(k--)
{
int x,y;cin>>x>>y;
if(llabs(x-xx)+llabs(y-yy)<xx||llabs(x-xx)+llabs(y-yy)<yy)
//如果这个数的曼哈顿距离小于到重点的x轴距离或者y轴距离 ,即可逃离
{
sum++;
}
}
cout<<sum;
return 0;
}