hdu5725

这题网上大多讲得很清楚就不说了。。。

http://blog.csdn.net/y1196645376/article/details/52187900//这个老哥讲得好

主要就是注意一下(long long)就好了,还有就是计数的关键是注意到我们可以把曼哈顿距离分拆成横和竖两个方向分别计算。

第一行的曼哈顿距离的贡献就是第二行,第三行,第四行,。。。哪些行的点到第一行的竖直距离是1 2 3 . 。 。 。 

第一列的曼哈顿距离贡献是第二列,第三列,第四列,。。。。。哪些列的点到第一列的横向距离是1 2 3 . 。 。 。 。 

对于一个点也进行分拆:

如一个点(i,j)

先计算竖向方向的距离和,有i个竖,所以是i*(j-1)*j/2;

横是i*(i-1)*j/2;

这样计算会带来一些问题;

就是一个G点会重复计算你用这个栗子调试下就明白了:

3 4
G###
##G#
####
2.2600

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
char mapp[1010][1010];
typedef long long ll;
struct pairr
{
	int i, j;
   ll linei, hengj;
};
pairr p[1500];
int n, m,t,tott;
ll sum = 0;
ll amount = 0;
bool com(pairr a, pairr b)
{
	return a.i < b.i;
}
bool com2(pairr a, pairr b)
{
	return a.j < b.j;
}
ll get(ll i, ll j)
{
	return j*((i*(i - 1)) / 2)+i*((j*(j-1))/2);
}
int main()
{
	scanf("%d", &t);
	while (t--)
	{
		tott = 0; sum = 0; amount = 0;
		scanf("%d%d", &n, &m);
		sum = (1ll*(m*n - 1)*(m + n)*m*n)/3;
		amount = 1ll*m*n*(m*n);
		getchar();
		for (int i = 1; i <= n; i++)
		{
			gets(mapp[i]+1);
			for (int j = 1; j <= m; j++)
			{
			
				if (mapp[i][j] == 'G')
				{
					p[tott].i = i; p[tott++].j = j;
					amount -= (m*n - 1-(tott-1)) * 2;
					amount--;
					sum -= (get(i, j) + get(n - i + 1, j) + get(i, m - j + 1) + get(n - i + 1, m - j + 1)) * 2;
					sum += (get(1, j) + get(i, 1) + get(1, m - j + 1) + get(n - i + 1, 1))*2;
				}
			}
		}
		for (int i = 0; i < tott; i++)
		{
			for (int j = 0; j < i; j++)
			{
				int p1 = abs(p[i].i - p[j].i); int p2 = abs(p[i].j - p[j].j);
				sum += (p1 + p2) * 2;
			}
		}
			sort(p, p + tott, com2);
			ll tempsum = 0;
			for (int i = 0; i < tott; i++)
			{
				tempsum += (n - p[i].i);
				p[i].linei = tempsum;
				if (p[i].j + 1 != p[i + 1].j || p[i].i < p[i + 1].i)
					tempsum = 0;
			}
			for (int i = 0; i < tott; i++)
			{
				if (p[i].linei)
					sum += (p[i].linei*(p[i].i - 1)) *4,
					p[i].linei = 0;
			}
			tempsum = 0;
			for (int i = tott - 1; i >= 0; i--)
			{
				if (tempsum)
					p[i].linei = tempsum;
				if (p[i].j - 1 != p[i - 1].j || p[i].i < p[i - 1].i)
					tempsum = 0;
				else
					tempsum += (n - p[i].i);
			}
			for (int i = 0; i < tott; i++)
			{
				if (p[i].linei)
					sum += (p[i].linei*(p[i].i - 1)) * 4,
					p[i].linei = 0;
			}
			tempsum = 0;
			sort(p, p + tott, com);
			for (int i = 0; i < tott; i++)
			{
				tempsum += (m - p[i].j);
				p[i].hengj = tempsum;
				if (p[i].i+1!= p[i + 1].i || p[i].j < p[i + 1].j)
					tempsum = 0;
			}
			for (int i = 0; i < tott; i++)
			{
				if (p[i].hengj)
				{
					sum += (p[i].j - 1)*(p[i].hengj) *4,
						p[i].hengj=0;
				}
			}
			tempsum = 0;
			for (int i = tott - 1; i >= 0; i--)
			{
				if (tempsum)
					p[i].hengj = tempsum;
				if (p[i].i - 1 != p[i - 1].i || p[i].j < p[i - 1].j)
					tempsum = 0;
				else
					tempsum += (m - p[i].j);
			}
			for (int i = 0; i < tott; i++)
			{
				if (p[i].hengj)
				{
					sum += (p[i].j - 1)*(p[i].hengj) * 4,
						p[i].hengj = 0;
				}
			}
			double rate = (sum*1.0) / (amount*1.0);
			printf("%.4llf\n", rate);
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值