zoukankan      html  css  js  c++  java
  • Google Kick Start 2020 Round B T4 Wandering Robot

    题意

    一个(n imes m)的矩形空间,起点是((1,1)),终点是((n,m))

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

    • 如果当前位于最后一行,那么下一步只能走向((x,y+1))
    • 如果当前位于最后一列,那么下一步只能走向((x+1,y))
    • 否则,以相等的概率走向((x,y+1))((x+1,y))中的一个。

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

    解题思路

    先不考虑黑洞。

    对于(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)处理就可以把数值压在能接受的范围内。再加上

    [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))了。

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

    记走到((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))的递推出来。

    假设上图中,黑色部分为黑洞,((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
    ", Case, ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ 1703 Find them, Catch them (数据结构-并查集)
    ProductHunt:创业公司产品猎场和秀场
    firedac数据集控件的公共祖先类——TFDAdaptedDataSet
    IDFTP连不上FTP服务器的解决方法
    SQLServer到底支持多少连接数的并发?
    日志
    权限
    DATASNAP中间件调用带OUTPUT参数的存储过程
    连接池中的连接超过数据库端的最大空闲时间
    firedac的TFDStoredProc动态创建并调用存储过程
  • 原文地址:https://www.cnblogs.com/zengzk/p/12732281.html
Copyright © 2011-2022 走看看