UVA557 Burger 題解

Sorato發表於2024-03-22

UVA557 Burger

題目大意

稱一個長度為 \(n\) 的01串是好的,當且僅當 \(0\)\(1\) 在該串中分別出現恰好 \(\frac n2\) 次,且該串的最後兩位相同。

現給定 \(n\)\(n\) 為偶數),求 該串是好的 的機率。

Solve

正難則反,考慮求出最後兩位不同的機率。

\(m=\frac n2\),那麼條件“最後兩位不同”等價於前 \(2m-2\) 位中,有 \(m-1\)\(0\)\(1\)

顯然該串滿足此條件的機率是:

\[P_n=\frac{{2m-2}\choose{m-1}}{2^{2m-2}}=\frac{{n-2}\choose{\frac n2-1}}{2^{n-2}} \]

即從前 \(2m-2\) 位中選出 \(m-1\) 位令其為 \(0\) 的方案數除以總方案數。而每一位上是 \(0\)\(1\) 有兩種選擇,所以共有 \(2^{2m-2}\) 種方案。

所以最後的答案就是 \(1-P\) 了。

然後考慮怎麼求組合數,顯然不能利用遞推求,時間和空間上都過不去,而用階乘和逆元的話,我不會。

考慮手推個遞推式,因為我們發現只需求 \(2i\choose i\),顯然不難推。

\[\begin{align} {2i\choose i}&=\frac{(2i)!}{i!\times i!}=\frac{2i\times(2i-1)\times\dots\times(i+1)}{i!}\\ \\\\ {2i+2\choose i+1}&=\frac{(2i+2)!}{(i+1)!\times (i+1)!}\\ &=\frac{(2i+2)\times(2i+1)\times\dots\times(i+2)}{(i+1)!}\\ &=(2i+2)\times(2i+1)\times\frac{2i\times(2i-1)\times\dots\times(i+1)}{(i+1)\times(i+1)!}\\ &=(2i+2)\times(2i+1)\times\frac{{2i\choose i}\times i!}{(i+1)\times(i+1)!}\\ &=2\times(2i+1)\times\frac{2i\choose i}{i+1}\quad ((2i+2)約掉(i+2)剩2,i!約掉(i+1)!剩(i+1))\\ 即:\\ {2i\choose i}&=2\times(2i-1)\times\frac{2i-2\choose i-1}{i}\\ 即:\\ {i\choose \frac i2}&=2\times(i-1)\times\frac{i-2\choose \frac i2-1}{\frac i2}=4\times(i-1)\times\frac{i-2\choose \frac i2-1}i\\\\ 將{i-2\choose \frac i2-1}代入得P_i&=\frac{{i-2}\choose{\frac i2-1}}{2^{i-2}}\\ 將{i\choose \frac i2}代入得P_{i+2}=\frac{i\choose \frac i2}{2^i}&=4\times(i-1)\times\frac{i-2\choose \frac i2-1}i\div2^i\\ &=4\times(i-1)\times\frac{i-2\choose \frac i2-1}{2^i}\div i\\ &=(i-1)\times\frac{i-2\choose \frac i2-1}{2^{i-2}}\div i\\ &=P_i\times(i-1)\div i\\ 即:\\ P_i&=P_{i-2}\times(i-1)\div i \end{align} \]

程式碼就很簡單了。

Code

#include<bits/stdc++.h>
#pragma GCC optimize(1,2,3,"Ofast","inline")
using namespace std;
#define int long long
inline int read()
{
	short f=1;
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int t,n,mi,m;
double ans[100010]={1}/*C(i/2,i)*/;
signed main()
{
	for(int i=2;i<=100000;i+=2)
		ans[i]=ans[i-2]*(i-1)/i;
	t=read();
	for(int i=1;i<=t;i=-~i)
		printf("%.4lf\n",1-ans[read()-2]);
	return 0;
}