燈燈燈

shaoyufei發表於2024-05-31

題目描述
有 n 盞紅燈,m 盞綠燈,每次隨機熄滅一盞,直到一種顏色的燈全部被熄滅,求剩下燈個數的期望。

輸入格式
兩個整數 n 和 m,分別表示紅燈個數和綠燈個數。

輸出格式
一個小數,四捨五入保留六位小數。

樣例
樣例輸入
10 20
樣例輸出
2.294372

感謝wwppcc的推導%%%%%%
一道究極煞筆的數論題
資料範圍1e9,很顯然不能dp,但dp仍能得部分分

DP暴力

實際上,根據"直到一種顏色的燈全部被熄滅"可以看出,如果不限資料範圍,這一道實際是red is good的變形,不同的是它有兩個初始狀態,但沒有終止(或者說,是dp的邊界),因此可以直接轉移:
\(f[i][j]=f[i-1][j]*\frac{i}{i+j}+f[i][j-1]*\frac{j}{i+j}\)

\(f[i][0]=i\)

\(f[0][j]=j\)

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=5001;
double f[N][N];
int n,m;
int main(){
	cin>>n>>m;
	for(int j=1;j<=m;j++) f[0][j]=j;
	for(int i=1;i<=n;i++) f[i][0]=i;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			f[i][j]=f[i-1][j]*i/(i+j)+f[i][j-1]*j/(i+j);
		}
	}
	cout<<setprecision(6)<<fixed<<f[n][m]<<endl;
}
(你怎麼知道我個唐氏對著int型的dp調了半天)

推式子

n個紅,m個綠,我們先假設:
最後一個是紅,那麼前面拿走的一定是綠(因為僅同一顏色的就立馬停止)
那麼先考慮紅的期望:
紅的總情況為:\(C^{n}_{m+n}\)
剩一個的(因為已經有一紅一綠固定了):\(C^{n-1}_{n+m-2}\)
那麼剩兩個的:\(C^{n-2}_{n+m-3}\)
剩n個的:\(C^{n-n}_{n+m-n-1}\)
那麼對於紅的期望,則有:

\(\frac{1*C^{n-1}_{n+m-2}+2*C^{n-2}_{n+m-3}+…………+n*C^{n-n}_{n+m-n-1}}{C^{n}_{n+m}}\)
image(以防看不清)

開始化簡
我們可以給分子的每一項都提個1,即:
\(C^{n-1}_{n+m-2}+C^{n-2}_{n+m-3}+…………+C^{n-n}_{n+m-n-1}+(2-1)*C^{n-2}_{n+m-3}+…………\)
剩n-1個的:\(C^{n-n+1}_{n+m-n}\)
\(C^{1}_{m+n-n}\)
因為\(C^{0}_{n+m-n-1}=C^{0}_{n+m-n}=1\)
那麼我們可以考慮將第n項和n-1項合併,利用公式\(C^m_{n+1}=C^m_n+C^{m-1}_n\)得:
\(C^{1}_{n+m-n}+C^{0}_{n+m-n}=C^{1}_{n+m-n+1}\)
又知n-2項為:\(C^{n-n+2}_{n+m-n+1}\)
即:\(C^{2}_{n+m-n+1}\)
而它又可以和合並的那一項接著合併,那麼對於提1的式子會有:
\(C^{n-1}_{n+m-2}+C^{n-2}_{n+m-3}+…………+C^{n-n}_{n+m-n-1}=C^{n-1}_{n+m-1}\)
而原分子還剩下:
\(C^{n-2}_{n+m-3}+2*C^{n-3}_{n+m-4}+…………+(n-1)*C^{n-n}_{n+m-n-1}\)
那麼考慮給剩下的項接著提1合併,最後整個分子為:
\(C^{n-1}_{n+m-1}+C^{n-2}_{n+m-2}+…………+C^{n-n}_{n+m-n}\)
很顯然,他們仍可以根據\(C^m_{n+1}=C^m_n+C^{m-1}_n\)合併,得:
\(C^{n-1}_{n+m}\)
那麼對於紅色的期望值則會有:
\(\frac{C^{n-1}_{n+m}}{C^{n}_{n+m}}\)
根據公式\(C^m_n=\frac{n!}{m!(n-m)!}\)可得:
\({C^{n-1}_{n+m}}=\frac{(n+m)!}{(n-1)![n+m-(n-1)]!}\)
即:\(\frac{(n+m)!}{(n-1)!(m+1)!}\)
\(C^{n}_{n+m}=\frac{(n+m)!}{n!(n+m-n)!}\)
即:\(\frac{(n+m)!}{n!m!}\)
兩個值做比,可得:
\(\frac{n!m!}{(n-1)!(m+1)!}\)
展開,約分,最後得:
\(\frac{n}{m+1}\)
綠色的話將n和m對調一下即可,結果是:
\(\frac{m}{n+1}\)
因此將兩個結果加和就是答案

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
int n,m;
double ans;
int main(){
	cin>>n>>m;
	ans=(double)n/(m+1)+(double)m/(n+1);
	cout<<setprecision(6)<<fixed<<ans<<endl;
}

相關文章