[氧化镍]阴阳两隔

280 篇文章 1 订阅

题目

题目描述
你正在听 T i w \sf Tiw Tiw 讲题。祂有时候讲阴间生成函数,有时候讲阳间(相对而言)数学推导,当然也可能讲了些完全超出你能力范围的东西(显然此类应为绝大多数)。

你认为 T i w \sf Tiw Tiw 在每讲完一个东西之后,有 p p p 的概率立刻停止。你认为某个时刻是 “勉强知道自己在干嘛” 的时刻,当且仅当目前 T i w \sf Tiw Tiw 讲过的阳间数学推导严格多于阴间生成函数。

现在,请问在 T i w \sf Tiw Tiw 一次讲题的过程中,“勉强知道自己在干嘛” 的时刻的期望数量。可以认为 T i w \sf Tiw Tiw 每次讲一个东西的时候,有 p 1 p_1 p1 的概率是阳间的,有 p 2 p_2 p2 的概率是阴间的。(显然有 1 − p 1 − p 2 1-p_1-p_2 1p1p2 的概率讲了一个完全听不懂的东西。)

数据范围与提示
1 ≥ p > 0 1\ge p>0 1p>0 p 1 ,    p 2 ,    1 − p 1 − p 2 p_1,\;p_2,\;1-p_1-p_2 p1,p2,1p1p2 均为非负。输入的数字不超过 5 5 5 位小数。

答案的绝对误差或者相对误差需要不超过 1 0 − 8 10^{-8} 108

思路

前言:经此一题,我终于意识到,神明是存在的,祂就在我身边。我是 T L Y \sf TLY TLY 太阳神教 的忠实信徒。

那么我们直接上数学推导吧。我希望这不会让你们感到头大。

第一步,随意的考虑某个 “知道自己在跪着听” 的时刻,三种情况(阳间、阴间、听不懂)的个数,然后算概率(因为贡献是 1 1 1,概率就是期望)。
a n s = ∑ a > b ≥ 0 ,    c ≥ 0 p 1 a    p 2 b    ( 1 − p 1 − p 2 ) c    ( 1 − p ) a + b + c − 1    ( a + b + c a + b ) ( a + b a ) ans=\sum_{a>b\ge 0,\;c\ge 0}p_1^a\;p_2^b\;(1-p_1-p_2)^c\;(1-p)^{a+b+c-1}\;{a+b+c\choose a+b}{a+b\choose a} ans=a>b0,c0p1ap2b(1p1p2)c(1p)a+b+c1(a+ba+b+c)(aa+b)

神谕:“显然我们会想到把这个东西放进去。” 即,记 p 1 ′ = p 1 ( 1 − p ) p_1'=p_1(1-p) p1=p1(1p),然后 p 2 ′ , p 3 ′ p_2',p_3' p2,p3 同理,那就可以直接写成 p 1 ′ p_1' p1 等的乘积。为了书写方便,一律去掉 ' 符号,还请留心。这里 p 3 p_3 p3 对应 1 − p 1 − p 2 1-p_1-p_2 1p1p2
a n s = 1 1 − p ∑ a > b ≥ 0 ,    c ≥ 0 p 1 a    p 2 b    ( a + b a )    p 3 c    ( a + b + c a + b ) ans={1\over 1-p}\sum_{a>b\ge 0,\;c\ge 0}p_1^a\;p_2^b\;{a+b\choose a}\;p_3^c\;{a+b+c\choose a+b} ans=1p1a>b0,c0p1ap2b(aa+b)p3c(a+ba+b+c)

这一步需要小心的是, p = 1 p=1 p=1 是有可能的!所以需要特判掉。而从这里开始,所有的 p ? p_? p? 都在 [ 0 , 1 ) [0,1) [0,1) 范围内,下面的定义域几乎都满足。

神谕:“发现 c c c 与另外两个独立,想办法去掉它。如果你对它比较熟悉,你可以直接指出:它就是 1 ( 1 − x ) a + b + 1 {1\over(1-x)^{a+b+1}} (1x)a+b+11 的生成函数开形式。” 即, 1 ( 1 − x ) a + b + 1 = ∑ i = 0 + ∞ ( i + a + b a + b ) x i    ( x < 1 ) {1\over(1-x)^{a+b+1}}=\sum_{i=0}^{+\infty}{i+a+b\choose a+b}x^i\;(x<1) (1x)a+b+11=i=0+(a+bi+a+b)xi(x<1),令 x = p 3 x=p_3 x=p3,枚举变量 i i i c c c 是等价的。
a n s = 1 1 − p ∑ a > b ≥ 0 p 1 a    p 2 b    ( a + b a )    1 ( 1 − p 3 ) a + b + 1 ans={1\over 1-p}\sum_{a>b\ge 0}p_1^a\;p_2^b\;{a+b\choose a}\;{1\over(1-p_3)^{a+b+1}} ans=1p1a>b0p1ap2b(aa+b)(1p3)a+b+11

又到了愉快的 “塞进去” 时间!为了书写方便,仍然去掉 ' 符号。
a n s = 1 ( 1 − p ) ( 1 − p 3 ) ∑ a > b ≥ 0 p 1 a    p 2 b    ( a + b a ) ans={1\over(1-p)(1-p_3)}\sum_{a>b\ge 0}p_1^a\;p_2^b\;{a+b\choose a} ans=(1p)(1p3)1a>b0p1ap2b(aa+b)

做到这里,其实已经有了一个完美的解决方案。设输出的概率是 P 1 , P 2 P_1,P_2 P1,P2,令 P 3 = 1 − P 1 − P 2 P_3=1-P_1-P_2 P3=1P1P2,式中 p 1 = P 1 ( 1 − p ) 1 − P 3 ( 1 − p ) p_1={P_1(1-p)\over 1-P_3(1-p)} p1=1P3(1p)P1(1p),令 q = 1 1 − p > 1 q={1\over 1-p}>1 q=1p1>1,运用一下糖水不等式则有
p 1 = P 1 q − P 3 ≤ 1 − P 3 q − P 3 ≤ w a t e r s u g a r 1 q = 1 − p p_1={P_1\over q-P_3}\le{1-P_3\over q-P_3}\overset{\overset{\scriptsize sugar}{water}}{\le}\frac{1}{q}=1-p p1=qP3P1qP31P3watersugarq1=1p

p 2 p_2 p2 同理。而 1 − p ≤ 0.99999 1-p\le 0.99999 1p0.99999,在 a + b > 3 × 1 0 6 a+b>3\times 10^6 a+b>3×106 时,幂已经小于 1 0 − 12 10^{-12} 1012 了,不会引起误差。而 a + b ≤ 3 × 1 0 6 a+b\le 3\times 10^6 a+b3×106 时,可以很简单的 d p \tt dp dp 求概率。这种方法的代码我附在最后,好奇的可以自行研究。

可是这里就体现出神与人的差距了。神无意吊打我,祂只是不自知地吊打了出题人。更不幸的是: T L Y \sf TLY TLY 就是神。

S a = ∑ b = 0 a − 1 ( a + b a )    p 2 b S_a=\sum_{b=0}^{a-1}{a+b\choose a}\;p_2^b Sa=b=0a1(aa+b)p2b,虽然这里并不是一个直接的生成函数展开式,但是我们可以 “错位相减”。这可能就是神的直觉吧!
S a − p 2 ⋅ S a = ∑ b = 0 a − 1 [ ( a + b a ) − ( a + b − 1 a ) ] ⋅ p 2 b − ( 2 a − 1 a ) p 2 a = ∑ b = 0 a − 1 ( a − 1 + b a − 1 ) ⋅ p 2 b − ( ⋯   ) = S a − 1 + ( 2 a − 2 a − 1 ) p 2 a − 1 − ( ⋯   ) S_a-p_2\cdot S_a=\sum_{b=0}^{a-1}\left[{a+b\choose a}-{a+b-1\choose a}\right]\cdot p_2^b-{2a-1\choose a}p_2^{a}\\ =\sum_{b=0}^{a-1}{a-1+b\choose a-1}\cdot p_2^b-(\cdots)=S_{a-1}+{2a-2\choose a-1}{p_2}^{a-1}-(\cdots) Sap2Sa=b=0a1[(aa+b)(aa+b1)]p2b(a2a1)p2a=b=0a1(a1a1+b)p2b()=Sa1+(a12a2)p2a1()

为了防止过长,有所省略。令
r a = ( 2 a − 2 a − 1 ) p 2 a − 1 − ( 2 a − 1 a ) p 2 a r_a={2a-2\choose a-1}p_2^{a-1}-{2a-1\choose a}p_2^a ra=(a12a2)p2a1(a2a1)p2a

递推式简写为
S a = S a − 1 + r a 1 − p 2 S_a={S_{a-1}+r_a\over 1-p_2} Sa=1p2Sa1+ra

一个很不错的 o b s e r v a t i o n \rm observation observation 1 − p 2 1-p_2 1p2 是一个定值。再考虑到它的递归出口 { S 0 = 0 r 1 = 1 − p 2 \begin{cases}S_0=0\\r_1=1-p_2\end{cases} {S0=0r1=1p2,显然我们可以直接考虑每个 r a r_a ra 最后得到的系数。所以
( 1 − p ) ( 1 − p 3 ) ⋅ a n s = ∑ a = 1 + ∞ p 1 a    S a = ∑ a = 1 + ∞ p 1 a ∑ i = 1 a r i ( 1 − p 2 ) a − i + 1 = ∑ i = 1 + ∞ r i    p 1 i ∑ a = i + ∞ p 1 a − i ( 1 − p 2 ) a − i + 1 = 1 1 − p 2 ∑ i = 1 + ∞ r i    p 1 i    1 − p 2 1 − p 2 − p 1 = 1 1 − p 1 − p 2 ∑ i = 1 + ∞ r i    p 1 i (1-p)(1-p_3)\cdot {\rm ans}=\sum_{a=1}^{+\infty}p_1^a\;S_a\\ =\sum_{a=1}^{+\infty}p_1^a\sum_{i=1}^{a}\frac{r_i}{(1-p_2)^{a-i+1}}\\ =\sum_{i=1}^{+\infty}r_i\;p_1^i\sum_{a=i}^{+\infty}\frac{p_1^{a-i}}{(1-p_2)^{a-i+1}}\\ ={1\over 1-p_2}\sum_{i=1}^{+\infty}r_i\;p_1^i\;{1-p_2\over 1-p_2-p_1}\\ =\frac{1}{1-p_1-p_2}\sum_{i=1}^{+\infty} r_i\;p_1^i (1p)(1p3)ans=a=1+p1aSa=a=1+p1ai=1a(1p2)ai+1ri=i=1+rip1ia=i+(1p2)ai+1p1ai=1p21i=1+rip1i1p2p11p2=1p1p21i=1+rip1i

那个地方,公比 p 1 1 − p 2 p_1\over 1-p_2 1p2p1 可靠吗?当然。因为 p 1 + p 2 < 1 p_1+p_2<1 p1+p2<1,具体原因就去 s u g a r    w a t e r \rm sugar\;water sugarwater 那一节比对吧。

于是我们竟然只需要求 ∑ i = 1 + ∞ r i    p 1 i \sum_{i=1}^{+\infty}r_i\;p_1^i i=1+rip1i 了耶!两个组合数分开考虑。第一项:
∑ i = 1 + ∞ ( 2 i − 2 i − 1 )    p 2 i − 1    p 1 i \sum_{i=1}^{+\infty}{2i-2\choose i-1}\;p_2^{i-1}\;p_1^i i=1+(i12i2)p2i1p1i

这东西似乎和卡特兰数很像。考虑用生成函数化简,记
C 1 ( x ) = ∑ i = 0 + ∞ ( 2 i i ) ⋅ x i C_1(x)=\sum_{i=0}^{+\infty}{2i\choose i}\cdot x^i C1(x)=i=0+(i2i)xi

同样试着写递推式。现实意义仍然是 n n n 0 0 0 n n n 1 1 1 的序列。还是可以考虑前缀 0 , 1 0,1 0,1 数量相同之处。不妨设第一位是 0 0 0,将其反转就是第一位为 1 1 1 的。那么前半部分是卡特兰数,后半部分还是 C 1 C_1 C1 。记卡特兰数的生成函数 1 − 1 − 4 x 2 x = C 0 ( x ) \frac{1-\sqrt{1-4x}}{2x}=C_0(x) 2x114x =C0(x),则有
C 1 ( x ) = 2 x ⋅ C 0 ( x ) ⋅ C 1 ( x ) + 1 ⇒ C 1 ( x ) = 1 1 − 4 x C_1(x)=2x\cdot C_0(x)\cdot C_1(x)+1\\ \Rightarrow C_1(x)=\frac{1}{\sqrt{1-4x}} C1(x)=2xC0(x)C1(x)+1C1(x)=14x 1

第二项是要减去的,绝对值为
∑ i = 1 + ∞ ( 2 i − 1 i ) ⋅ p 2 i ⋅ p 1 i C 2 ( x ) = ∑ i = 1 + ∞ ( 2 i − 1 i ) ⋅ x i \sum_{i=1}^{+\infty}{2i-1\choose i}\cdot p_2^i\cdot p_1^i\\ C_2(x)=\sum_{i=1}^{+\infty}{2i-1\choose i}\cdot x^i i=1+(i2i1)p2ip1iC2(x)=i=1+(i2i1)xi

稍微麻烦点。它是在坐标系内行走到 ( i , i − 1 ) (i,i-1) (i,i1) 的方案数。如果第一步是向右,那么它就是上面的 C 1 C_1 C1 的情形;如果第一步是向上,那么必然经过 ℓ : x = y \ell:x=y :x=y 这条直线,分成两部分,前半部分是卡特兰数,后半部分又是 C 2 C_2 C2 。所以
C 2 ( x ) = x ⋅ C 1 ( x ) + x ⋅ C 0 ( x ) ⋅ C 2 ( x ) ⇒ C 2 ( x ) = 2 x 1 − 4 x + 1 − 4 x C_2(x)=x\cdot C_1(x)+x\cdot C_0(x)\cdot C_2(x)\\ \Rightarrow C_2(x)={2x\over{1-4x+\sqrt{1-4x}}} C2(x)=xC1(x)+xC0(x)C2(x)C2(x)=14x+14x 2x

于是终于写出
a n s = p 1 ⋅ C 1 ( p 1 p 2 ) − C 2 ( p 1 p 2 ) ( 1 − p ) ( 1 − p 3 ) ( 1 − p 1 − p 2 ) ans={p_1\cdot C_1(p_1p_2)-C_2(p_1p_2)\over(1-p)(1-p_3)(1-p_1-p_2)} ans=(1p)(1p3)(1p1p2)p1C1(p1p2)C2(p1p2)

当然,这里 p 1 p 2 ≤ 1 4 p_1p_2\le\frac{1}{4} p1p241 才行欸!其实这是成立的。因为 { p 1 = P 1 ( 1 − p ) 1 − ( 1 − P 1 − P 2 ) ( 1 − p ) p 2 = P 2 ( 1 − p ) 1 − ( 1 − P 1 − P 2 ) ( 1 − p ) p 3 = ( 1 − P 1 − P 2 ) ( 1 − p ) \begin{cases}p_1={P_1(1-p)\over 1-(1-P_1-P_2)(1-p)}\\p_2={P_2(1-p)\over 1-(1-P_1-P_2)(1-p)}\\p_3=(1-P_1-P_2)(1-p)\end{cases} p1=1(1P1P2)(1p)P1(1p)p2=1(1P1P2)(1p)P2(1p)p3=(1P1P2)(1p),那么你很容易发现
q = 1 1 − p > 1 ,    P 3 = 1 − P 1 − P 2 ≤ 1 p 1 p 2 = P 1 P 2 ( q − P 3 ) 2 ≤ A . G . ( P 1 + P 2 2 ) 2 ( q − P 3 ) 2 ≤ ( 1 − P 3 ) 2 4 ( q − P 3 ) 2 ≤ w a t e r s u g a r 1 4 q 2 < 1 4 q=\frac{1}{1-p}>1,\;P_3=1-P_1-P_2\le 1\\ p_1p_2=\frac{P_1P_2}{(q-P_3)^2}\overset{A.G.}{\le}\frac{({P_1+P_2\over 2})^2}{(q-P_3)^2}\le\frac{(1-P_3)^2}{4(q-P_3)^2}\overset{\overset{\scriptsize sugar}{water}}{\le }\frac{1}{4q^2}<\frac{1}{4} q=1p1>1,P3=1P1P21p1p2=(qP3)2P1P2A.G.(qP3)2(2P1+P2)24(qP3)2(1P3)2watersugar4q21<41

如果你愿意的话,你也可以把 a n s ans ans 写成关于输入数据的式子。

就这样,这道题就被 无精度误差(除了 d o u b l e \tt double double 自动丢失精度)算出来了。 T L Y \sf TLY TLY 太阳神 永生!

代码

#include <bits/stdc++.h>
int main(){
	freopen("augury.in","r",stdin);
	freopen("augury.out","w",stdout);
	double p1, p2, p3, p; int T;
	for(scanf("%*d%d",&T); T; --T){
		scanf("%lf %lf %lf",&p1,&p2,&p);
		if(p == 1){ // must end immediately
			printf("%.10f\n",p1); continue;
		} else p3 = 1-p1-p2;
		double ans = 1/(1-p)/(1-p3*(1-p));
		p1 /= 1/(1-p)-p3, p2 /= 1/(1-p)-p3;
		double k = 1-4*p1*p2; // 1-4x
		ans *= p1/sqrt(k)-2*p1*p2/(k+sqrt(k));
		printf("%.10f\n",ans/(1-p1-p2));
	}
	return 0;
}

以及那个卡精度的方法:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
double qkpow(double b,int q){
	double a = 1;
	for(; q; q>>=1,b*=b)
		if(q&1) a *= b;
	return a;
}

const int MaxN = 3000005;
double f[MaxN]; 

int main(){
	readint();
	for(int T=readint(); T; --T){
		double p1, p2, p;
		scanf("%lf %lf %lf",&p1,&p2,&p);
		if(p == 1){ // must end immediately
			printf("%.10f\n",p1);
			continue;
		}
		double p3 = 1-p1-p2;
		p1 *= (1-p), p2 *= (1-p), p3 *= (1-p);
		p1 /= (1-p3), p2 /= (1-p3);
		f[0] = 0, f[1] = p1, f[2] = p1*p1;
		// tmp = C(i-1,i/2)*pow(p1,i/2)*pow(p2,i/2)
		double tmp = p1*p2;
		double ans = f[1]+f[2];
		for(int i=3; i<MaxN; ++i){
			if(!(i&1)) tmp *= p1*p2*
				(i-1-(i>>1))/(i>>1);
			tmp *= (i-1); tmp /= (i-1-(i/2));
			if(i&1) f[i] = f[i-1]*(p1+p2)+tmp*p1;
			else f[i] = f[i-1]*(p1+p2)-tmp;
			ans += f[i]; // add them up
		}
		ans /= (1-p), ans /= (1-p3);
		printf("%.10f\n",ans);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值