51Nod 诺德街
题意
有n个点, 一个人会从1号点走到n号点, 每个点有\(p_i\)的概率停下,如果到n还没停下, 就往回走, 不断循环....
求他走的的期望距离
题解
不错的概率题, 之前在初赛做过类似的才想的出来(这种做法说实话有点不符合我的思考逻辑
(在我的思考中, 一般认为递推式是单方向的, 很少考虑当作方程来求解
首先考虑一下递推式, 我们设\(d_i = 1-p_i\) (不会停下的概率), \(f_i\)表示以i为起点期望走的距离, 有:
\[f_i = p_i*0 + d_i*(f_{i+1}+1)
\]
(停下距离为0, 否则距离为以下个点为起点走距离, 加上这个点走到下个点的距离(1) )】
(当i>n时,i=2*n-i;
答案就是f1, 考虑如何求解f1
容易发现, 我们可以通过把f1当作一个未知量求解:
\(f1\)和\(f2\)的关系必然是\(f_1 = af_2 + b\) , (这里的a,b是系数, 可以由递推式求出来, 当这里我们不关心具体的值, 只是说明fi
的形式
然后: \(f_2 = a'f_3 + b', f_3=a''f_3 + b'', ..... f_n = a'''f_{n-1}+b'''\)
把f1当作未知项保留经行计算, 最后必然得到:
\(f_1 = af_1 + b\) (a,b与上文a,b不同)
这时候, 很神奇, 但是又很简单的操作出现了!!!
移项!
是的!\(af_1\)移动到左边
\((1-a)f_1 = b\)
\(\Rightarrow f1 = \frac b {(1-a)}\)
然后就随便你怎么做了, 把系数求出来就好了
实现
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
int read(){
int num=0, flag=1; char c=getchar();
while(!isdigit(c) && c!='-') c=getchar();
if(c=='-') c=getchar(), flag=-1;
while(isdigit(c)) num=num*10+c-'0', c=getchar();
return num*flag;
}
const int N = 2000500;
const ll mod = 1e9+7;
ll A, B, C;
ll p[N], f[N][2];
int n;
ll ksm(int x, int k){
if(k == 0) return 1;
ll res = ksm(x, k/2);
if(k % 2) return res*res%mod*x%mod;
return res*res%mod;
}
int main(){
n = read();
p[1]=read(), A=read(), B=read(), C=read();
for(int i=2; i<=n; i++){
p[i] = p[2*n-i] = (A*p[i-1]%mod*p[i-1]%mod + B*p[i-1]%mod + C)%mod;
}
for(int i=1; i<=n*2-1; i++){
p[i] = ((1-p[i])%mod+mod)%mod;
}
f[2*n-1][0] = 1;
for(int i=2*n-2; i>=1; i--){
f[i][0] = (p[i]*f[i+1][0])%mod;
f[i][1] = (p[i]*f[i+1][1]%mod + p[i])%mod;
}
ll ans = (f[1][1] * ksm(((1-f[1][0])%mod+mod)%mod, mod-2))%mod;
cout << ans << endl;
return 0;
}
/*10 2333 1 2 3*/