【题解】CF24D Broken Robots(收敛性)

【题解】CF24D Broken Robots

http://codeforces.com/problemset/problem/24/D

解1(不会写,口胡的)

获得一个比较显然的转移式子

\(dp(i,j)\)代表在\((i,j)\)坐标需要期望的走的次数

\[dp(i,j)=0.25(1+dp(i-1,j)+dp(i,j-1)+dp(i,j+1)) \]

然而我们可以发现这个式子不满足无后效性..也找不到一种合适的顺序DP。

我们发现可以高斯消元,但是\(O(n^4)\)的复杂度我们接受不了。

式子里面的\(dp(i-1,j)\)是上一行的事情,不需要考虑,直接转移即可,我们把\(dp(i,j)\)抽象为\(x_j\)

那么我们考虑的是。

\[x_j=0.25(1+l_j+x_{j-1}+x_{j+1}) \]

写成划一下

\[-0.25x_{j-1}+x_j-0.25x_{j+1}=0.25l_j+0.25 \]

写成矩阵

\[\begin{pmatrix} 1&-0.25&0& 0&0&0&0.25l_1+0.25 \\ -0.25&1&-0.25& 0&0&0&0.25l_2+0.25 \\ 0&-0.25&1&-0.25&0&0&0.25l_3+0.25 \\ 0&0&-0.25&1&-0.25&0&0.25l_4+0.25 \\ 0&0&0&-0.25&1&-0.25&0.25l_5+0.25 \\ 0&0&0&0&-0.25&1&0.25l_6+0.25 \end{pmatrix} \]

魔改一下高斯消元即可。

解2

众所周知,概率函数具有收敛性。 并且是指数地收敛的。又因为期望的式子里有概率作为因子,所以它应该是收敛的。(其实不是应该!是一定!若概率收敛则期望收敛(特殊情况除外),具体说明可以把概率和随机变量分开DP!)

好,既然我们已经知道了这个函数具有收敛性,那么我们就让他在每一行就多转移几次就好了。具体操作就是让每个点按照顺序每次从左边转移过来一次,从右边转移过来一次。重复这个步骤随便多少次就好了。

由于精度只要\(10^{-4}\),我们只需要\(\log_{\frac 1 3}10^{-4}=9\)次就好了。此处的分析是错误的,请高手说明一下QAQ。注意,这里的"概率函数的收敛"性是抽出一行看的,不能在转移的时候把自己的\(0.25\)和上一行的\(0.25l\)加进来,不然显然是个发散的函数。

为了方便统计答案,我们反着dp,毕竟从最后一行到起点的期望步数=从起点到最后一行的期望步数。

\(dp(i,j)\)表示从最后一行到这一点\((i,j)\)的期望步数。

转移:

\[dp(i,j)=1/dr[i][j]\times (dp[i+1][j]+dp[i][j-1,j,j+1])+1 \]

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
const int maxn=1e3+5;
typedef long double lb;
lb dp[maxn][maxn],ans;
const lb qt[]={0,(lb)1.0/1,(lb)1.0/2,(lb)1.0/3,(lb)1.0/4};
int cnt;
int n,m;
int x,y;
int main(){
      n=qr();m=qr();
      x=qr();y=qr();
      const int lit=50000000/(m)/(n-x+1);
      for(register int t=n-1;t>=x;--t){
	    for(register int t0=1;t0<=lit;++t0){
		  if(m>1)
			dp[t][1]=qt[3]*(dp[t+1][1]+dp[t][2]+dp[t][1])+1,dp[t][m]=qt[3]*(dp[t+1][m]+dp[t][m-1]+dp[t][m])+1;
		  if(m==1) dp[t][1]=qt[2]*(dp[t][1]+dp[t+1][1])+1;
		  for(register int i=2;i<m;++i)
			dp[t][i]=qt[4]*(dp[t+1][i]+dp[t][i-1]+dp[t][i]+dp[t][i+1])+1;
	    }
      }
      cout.precision(10);
      cout<<dp[x][y]<<endl;
      return 0;
}
//18.0038068653

posted @ 2019-06-01 11:03  谁是鸽王  阅读(230)  评论(0编辑  收藏  举报