這是一道2011年區域賽原題改編,難度頗高,雖然聽了雨巨的課但是還是沒做出來,看了題解后如夢方醒,遂寫此篇題解。
首先,我們可以設為吉吉囯國王在隊列長度為i的隊列中,處於j位置的狀態,從而可以推出狀態轉移方程如下:


方程(3)中因爲國王本不在隊列中,因此如果飯堂關門,國王也無法躋身與前k人中,因此無需增加p4.
預熱工作準備結束,下面進入正題。我們觀察方程(1),(2),(3)可知方程左右兩邊有相同項,從而我們可以對公式中加粗部分進行移項處理,從而可以得到新的方程組如下:

令:

我們通過觀察可以發現方程(2)和(3)中的是可以在循環過程中被直接求出的,因此我們可以將它當作常數來看待,我們令為常數項,從而可以得到


從而方程(2)的後兩項,方程(1)的最後一項與方程(3)的最後一項我們可以將其看作是常數來處理,進而我們可以推出一系列數列式:


現在我們所存在的問題是無法算出中的, 但是我們通過上面的數列可以發現,這件事是可以解決的,我們只需要將上面的式子往下面帶入,這樣就可以在最後一個式子中得到一個關於dp[i][i]的一元一次方程從而,就可以得出答案了。敲了那麽多累死了(:-)),直接上代碼了

#include<iostream>
#include<iomanip>
using namespace std;
double dp[2010][2010];
double c[2010]/*常數數組*/,p[2010]/*係數數組*/;
#define eps 1e-10

int main()
{
    int n,m,k;
    double p1,p2,p3,p4;
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>m>>k>>p1>>p2>>p3>>p4;
    if(p4<eps){
        cout<<"0.00000\n";
        return 0;
    }//此處是大坑,如果p4太小就直接返回0.
    double p12=p2/(1-p1);
    double p13=p3/(1-p1);
    double p14=p4/(1-p1);
    p[0]=1;//數列帶入時的係數數組
    for(int i=1;i<=n;i++){
        p[i]=p[i-1]*p12;
    }//計算的係數
    dp[1][1]=p4/(1-p1-p2);//dp[1][1]可直接算出
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            if(j<=k){
                c[j]=dp[i-1][j-1]*p13+p14;//算不同情況下的係數
            }
            else c[j]=dp[i-1][j-1]*p13;
        }
        double temp=0;
        for(int j=1;j<=i;j++){
            temp+=p[i-j]*c[j];
        }//數列帶入得到的係數
        dp[i][i]=temp/(1-p[i]);//計算得到dp[i][i]
        dp[i][1]=p12*dp[i][i]+p14;//計算dp[i][1]
        for(int j=2;j<i;j++){
            dp[i][j]=dp[i][j-1]*p12+c[j];
        }//帶入數列求出其他值
    }
    cout<<fixed<<setprecision(5)<<dp[n][m];
    return 0;
}