【题解】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

转载于:https://www.cnblogs.com/winlere/p/10958862.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值