1. 程式人生 > >BZOJ 3029 守護者的挑戰

BZOJ 3029 守護者的挑戰

是把 \n 所有 進行 else 小數 continue 一道 我們

打開了黑魔法師Vani的大門,隊員們在迷宮般的路上漫無目的地搜尋著關押applepi的監獄的所在地。突然,眼前一道亮光閃過。“我,Nizem,是黑魔法聖殿的守衛者。如果你能通過我的挑戰,那麽你可以帶走黑魔法聖殿的地圖……”瞬間,隊員們被傳送到了一個擂臺上,最初身邊有一個容量為K的包包。

擂臺賽一共有N項挑戰,各項挑戰依次進行.第i項挑戰有一個屬性\(a_i\),如果\(a_i>=0\),表示這次挑戰成功後可以再獲得一個容量為\(a_i\)的包包;如果\(a_i=-1\),則表示這次挑戰成功後可以得到一個大小為1 的地圖殘片。地圖殘片必須裝在包包裏才能帶出擂臺,包包沒有必要全部裝滿,但是隊員們必須把 獲得的所有的地圖殘片都帶走(沒有得到的不用考慮,只需要完成所有N項挑戰後背包容量足夠容納地圖殘片即可)

,才能拼出完整的地圖.並且他們至少要挑戰成功L次才能離開擂臺。

隊員們一籌莫展之時,善良的守衛者Nizem幫忙預估出了每項挑戰成功的概率,其中第i項挑戰成功的概率為\(p_i\)%。現在,請你幫忙預測一下,隊員們能夠帶上他們獲得的地圖殘片離開擂臺的概率。

\(input\)

第一行三個整數N,L,K.

第二行N個實數,第i個實數\(p_i\)表示第i項挑戰成功的百分比.

第三行N個整數,第i個整數\(a_i\)表示第i項挑戰的屬性值.

\(output\)

一個整數,表示所求概率,四舍五入保留6位小數.

\(0<=N<=200,0<=k<=2000,0<=L<=N\)

\(-1<=a_i<=1000,0<=p_i<=100\)

\(f[i][j][k]\)表示經過i項挑戰,當前容量為j,有k項挑戰獲得了勝利的概率.

因為最多只有200場挑戰,每次挑戰最多得到一個大小為1的地圖殘片,所以最多消耗200的背包容量,即j的最小值為-200,我們最多也只需要200的背包容量,即j的最大值為200,因為數組對負下標的操作不方便,所以不妨把\([-200,200]\)平移到\([0,400]\)來,相當於把200看作0,\(j>200\)表示背包容量有剩余,\(j<200\)表示還有碎片裝不下.

轉移只有兩種,即這次挑戰成功/失敗.

int N,L,K,a[205];
double ans,win[205],lose[205];
double f[205][405][205];
int main(){
    N=read();L=read();K=read();
    if(K>200)K=200;
//應該不會有人跟我一樣,寫成if(k>400)k=400吧
//我們只是把[-200,200](看作)移到[0,400]
//k本身的意義不變,背包容量最大為200就足夠了
    f[1][K+200][0]=1;//初始化
    for(int i=1;i<=N;i++){
        double ch;cin>>ch;
        win[i]=(double)ch/100.0;
        lose[i]=(double)1.0-win[i];
    }
//把每一次挑戰的勝率和敗率分別用兩個數組存下
    for(int i=1;i<=N;i++){
        a[i]=read();
    }
    for(int i=1;i<=N;i++)
    for(int j=0;j<=400;j++)
    for(int k=0;k<N;k++){
        if(f[i][j][k]==0)continue;
        f[i+1][j][k]+=f[i][j][k]*lose[i];
//這是第i次(也就是前i+1次)挑戰失敗的狀態轉移
        if(a[i]>=0){//表示這次勝利且獲得背包容量
            int cnt=f[i][j][k]*win[i];//偷懶,後面多次用到
            if(j+a[i]>400)//超過400移回來
                f[i+1][400][k+1]+=cnt;
            else f[i+1][j+a[i]][k+1]+=cnt
        }
        else f[i+1][j-1][k+1]+=cnt;//表示這次勝利且獲得碎片
    }
    N++;
//我們要知道第n次的結果,也就是要知道前n+1次的結果
    for(int j=200;j<=400;j++)
        for(int k=L;k<N;k++)
            ans+=f[N][j][k];
//j在[200,400]範圍內才表示背包容量有剩余
//因為要至少取得L次勝利,最多獲得 當前的N - 1 次勝利
    printf("%.6lf\n",ans);
    return 0;
}

BZOJ 3029 守護者的挑戰