Google Kick Start 2020 Round B T4 Wandering Robot

题意

一个\(n \times m\)的矩形空间,起点是\((1,1)\),终点是\((n,m)\)c++

假设当前位于\((x,y)\)spa

  • 若是当前位于最后一行,那么下一步只能走向\((x,y+1)\)
  • 若是当前位于最后一列,那么下一步只能走向\((x+1,y)\)
  • 不然,以相等的几率走向\((x,y+1)\)\((x+1,y)\)中的一个。

矩形空间中有一个小的矩形黑洞,用左上角和右下角的坐标表示,走进黑洞视为游戏失败,走到\((n,m)\)视为游戏成功,问游戏成功的几率。code

解题思路

先不考虑黑洞。blog

对于\(1 \leq x < n, 1 \leq y < m\),走到\((x,y)\)一共有\(C_{x+y-2}^{x-1}\)种可能的路径,而后走每一条可能的路径的几率为\(\frac{1}{2^{x+y-2}}\),因此走到\((x,y)\)的几率是\(\frac{C_{x+y-2}^{x-1}}{2^{x+y-2}}\)游戏

可是\(n,m\)的取值最高能够到\(1e5\),若是不加处理会炸精度,若是使用\(\log\)处理就能够把数值压在能接受的范围内。再加上it

\[2^{\log(\frac{C_{x+y-2}^{x-1}}{2^{x+y-2}})} = 2 ^ {\log((x + y - 2)!)-\log((y-1)!) - -\log((x-1)!) - x -y +2} \]

\(O(n)\)预处理出\(\log(i!)\)后就能够方便的计算\(P(x,y)\)了。class

而后根据规则,最后一行和最后一列的几率要另外算。这里仅以最后一行为例,最后一列也是用一样的方法。方法

记走到\((x,y)\)的几率为\(P(x,y)\),那么若是\((x,y)\)位于最后一行,则\(P(x,y)=P(x,y-1)+\frac{1}{2}P(x-1,y)\)。而后\(P(1,n)\)很容易推出等于\(\frac{1}{2^{n-1}}\),因此这一行的几率就能够\(O(n)\)的递推出来。im

假设上图中,黑色部分为黑洞,\((1,1)\)位于坐上角,那么很容易就能够得出游戏成功的几率为走到灰色格子的几率之和。将以前推导出的公式代入便可。总结

总结

早上七点的比赛差点错过了。前三题几乎都是直接秒,可是卡在了第四题。公式都推对了,可是没有想到炸精度怎么处理。脑海中出现了以前llg想在学校月赛搞用log处理大数的出题思路,可是看精度一直以为不太行,而后就下班了,哪想到这就是正解。果真有时候就应该xjbg。

而后补题的时候又是由于担忧精度问题用了long double,而后各类TLE,换成double就过了。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;

double lg[N], lstr[N], lstc[N];
int main()
{
#ifdef BACKLIGHT
    freopen("in.txt", "r", stdin);
#endif

	lg[0] = 0;
	for (int i =1; i <= 2e5; ++i) lg[i] = lg[i-1] + log2(i);

	int T;
	scanf("%d", &T);
	for (int Case = 1; Case <= T; Case ++) {
		int n, m, l, r, u, d;
		scanf("%d %d %d %d %d %d", &n, &m, &l, &u, &r, &d);

		lstr[1] = pow(2, lg[1 + n - 2] - lg[1 - 1] - lg[n - 1] - 1 - n + 2);
		for (int i = 2; i <= m; i++) {
			lstr[i] = lstr[i-1] + 0.5 * pow(2, lg[i + (n-1)- 2] - lg[i - 1] - lg[(n-1) - 1] - i - (n-1) + 2);
		}

		lstc[1] = pow(2, lg[1 + m - 2] - lg[1 - 1] - lg[m - 1] - 1 - m + 2);
		for (int i = 2; i <= n; i++) {
			lstc[i] = lstc[i-1] + 0.5 * pow(2, lg[i + (m-1)- 2] - lg[i - 1] - lg[(m-1) - 1] - i - (m-1) + 2);
		}

		double ans = 0, tmp;
		for (int i = 1; i <= l - 1; ++i) {
			int D = l + d - i;
			if(D > m) continue;
			else if(D == m) {
				ans += lstc[i];
			}
			else {
				tmp = lg[i + D - 2] - lg[i - 1] - lg[D - 1] - i - D + 2;
				ans += pow(2, tmp);
			}
		}

		for (int i = 1; i <= u - 1; ++i) {
			int R = r + u - i;
			if(R > n) continue;
			else if(R == n) {
				ans += lstr[i];
			}
			else {
				tmp = lg[i + R - 2] - lg[i - 1] - lg[R - 1] - i - R + 2;
				ans += pow(2, tmp);
			}
		}

		printf("Case #%d: %.12lf\n", Case, ans);
	}
	return 0;
}
相关文章
相关标签/搜索