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*/
原文地址:https://www.cnblogs.com/ltdjcoder/p/15411482.html