1. 程式人生 > >NOIP模擬 取書問題【概率期望dp】

NOIP模擬 取書問題【概率期望dp】

題目描述

有n個同學坐成一列,按從前往後的順序傳n本書,第i本數是第i新的,其中第i個同學會從n-i+1本課本中選一本並把剩下的書傳給後面的一位同學,第i個同學在挑選課本的時候滿足 如下過程:
1.如果只剩一本書,則一定拿走,否則轉步驟2;
2.從剩下的數中抽出最新的一本。
3.有a[i]的概率選擇這本書並結束選擇,1-a[i]個概率將這本書傳給後面的同學並回到步驟1。
現在問最後一名同學拿到的數在新舊排名的期望。

傳送門:http://www.accoders.com/problem.php?cid=1697&pid=2

解題思路

考慮一般的演算法瓶頸在我們需要記錄拿走的書的集合,但如果我們知道最後一位同學拿的書的排名為 x,那麼排名在 x 之前的書對 x 產生的貢獻只與剩餘的本數(因為一個人拿每本書的概率是相同的)有關,排名在 x 之後的同理。

所以我們先列舉最後一位同學拿的書的排名 x,再考慮 DP 概率,記 f[i][j][k]表示前i 個同學拿書時還剩下 j 本書排名小於等於 x,k 本書排名大於 x,可以轉移到 f[i+1][j-1][k]或f[i+1][j][k-1],轉移係數為第i個同學拿前j-1新的書的概率和拿後k新的書(不能拿第x本),可以O(n2n2)預處理後轉移係數做到 O(1)轉移,f[n][1][0]就是最後一個同學拿 x 的概率。
時間複雜度 O(n4),期望得分 80 分。

最後我們發現在確定 x,i,j 後,k 的值是可以算出的,所以省去一維狀態。
時間複雜度 O(n3),期望得分 100 分。

附上程式碼

#include<bits/stdc++.h>
const int N=303,M=1000000007;
int n,x,p[N][N];
long long f[N],now,ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d",&x);
        p[i][1]=x,now=1-x;
        for(int j=2;j<=n-i;j++)
        {
            p[i][j]=(p[i][j-1]+now*x)%M;
            now=now*(1-x)%M;
        }
        p[i][n-i+1]=1;
    }
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<n;i++)
        for(int j=1;j<=n-i;j++)
            f[j]=(f[j]*(1-p[i][j])+f[j+1]*p[i][j])%M;
    printf("%d",(f[1]+M)%M);
    return 0;
}

若您覺得此篇部落格寫得不錯,請別忘了點贊並關注我哦 >_<