3053. 【NOIP2012模拟10.25】旅行

63 篇文章 0 订阅
29 篇文章 13 订阅

Description

给定一个n行m列的字符矩阵,’.’代表空地,’X’代表障碍。移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍。

计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从起点移动到终点最短耗时的平均值。

每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:

 

.X

X.
 

Input

第一行两个整数n, m。 

接下来n行,每行m个字符’.’或’X’。

Output

平均耗时,保留4位小数,四舍五入。

Sample Input

2 2
..
.X

Sample Output

0.8889

Data Constraint

Hint

2<=n,m<=1000

Solution

先解决前50%:所有两点间的曼哈顿距离和。

之间的曼哈顿距离等于。先计算前一部分的和。枚举两行i,j。观察到:随便从这两行中各取一个点,这两点的x坐标之差相同。因此,这两行所有点对的就等于:{第i行空地的数量}*{第j行空地的数量}*|i-j|*2。

计算的方法完全相同,略过。两部分答案相加,最后除以空地总数的平方,就得到最终答案。

 

要解决后50%,关键是要观察到,从A走到B的耗时,要么等于AB的曼哈顿距离,要么等于AB的曼哈顿距离+2。也就是至多绕行一次。这是由题目中的条件“不会有两个X封锁住对角线”保证的。

那么,怎样的点对需要绕行呢,观察:

......

..X...

....X.

.X....

......

X.....

......

......

..X...

....X.

.X....

......

X.....

......

......

..X...

....X.

.X....

.....X

X.....

......

上图中红点到蓝点需要绕行。从直观上来看,一个X下方的点到这个X上方的点需要绕行。如果这个X右边一列(或者左边一列)包含X且本列X之上方,那么到这个X上方的点也需要绕行。横过来考虑是类似的。

根据以上规律,统计出需要+2的点对数加入答案即可AC本题。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 1010
using namespace std;
double ans;
ll tot,sum;
int n,m,x[N],y[N],dx[N],dy[N],t,k;
char c[N][N];
int main(){
	scanf("%d%d\n",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%c",&c[i][j]);
			if(c[i][j]=='X'){dx[j]=i;dy[i]=j;}
			else{x[i]++;y[j]++;tot++;}
		}
		scanf("\n");
	}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			ans+=x[i]*x[j]*(abs(i-j))*2;
	for(int i=1;i<=m;i++)
		for(int j=i+1;j<=m;j++)
			ans+=y[i]*y[j]*(abs(i-j))*2;
	for(int i=1;i<=m;i++) if(dx[i]){
		t=dx[i]-1;
		k=i;
		while(dx[k-1]&&dx[k-1]<dx[k]) t+=(dx[--k]-1);
		k=i;
		while(dx[k+1]&&dx[k+1]<dx[k]) t+=(dx[++k]-1);
		ans+=t*(n-dx[i])<<2;
	}
	for(int i=1;i<=n;i++) if(dy[i]){
		t=dy[i]-1;
		k=i;
		while(dy[k-1]&&dy[k-1]<dy[k]) t+=(dy[--k]-1);
		k=i;
		while(dy[k+1]&&dy[k+1]<dy[k]) t+=(dy[++k]-1);
		ans+=t*(m-dy[i])<<2;
	}
	tot=tot*(tot-1)+tot;
	printf("%.04lf",ans/tot);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/88806158

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值