SGU 422 Fast Typing(機率DP)

 

題目大意

 

某人在打字機上打一個字符串,給出了他打每一個字符出錯的機率 q[i]。 打一個字符須要單位1的時間,刪除一個字符也須要單位1的時間。在任意時刻,他能夠花 t 的時間檢查整個打出來的字符串,而且從當前光標刪除到第一個出錯的位置(留下的字符串要麼爲空,要麼每一個字符都是對的)。問你,他正確的打完該字符串最少須要花費的時間的指望值是多少php

字符串的長度小於等於3000ios

題意有點繞,具體能夠看看原題是怎麼描述的ide

 

作法分析

 

首先肯定這是一個機率DP的問題。優化

定義狀態 f[i] 表示正確的打完前 i 個字符之後,最少還須要多少時間正確的打完全部字符spa

能夠這樣轉移:日後連續打 j 個字符以後再來花時間檢查字符串,而且刪除,具體的轉移方程就是這樣的:code

        對於一個具體的 jblog

        令 g[i][j]= j+t字符串

                    +q[i+1]*(f[i]+j)  // 在第 i+1 位出錯get

                    +p[i+1]*q[i+2]*(f[i+1]+j-1)  // 在第 i+2 位出錯string

                    +p[i+1]*p[i+2]*q[i+3]*(f[i+2]+j-2)  // 在第 i+3 位出錯

                    +......

                    +p[i+1]*p[i+2]*p[i+3]*...*q[i+j]*(f[i+j-1]+1)  // 在第 i+j 位出錯

                    +p[i+1]*p[i+2]*p[i+3]*...*p[i+j]*f[i+j]  // 連續打的 k 個字符所有正確

上式中,p[i] 表示第 i 個字符正確的機率,q[i] 表示第 i 個字符錯誤的機率,p[i]+q[i]=1

考慮到上式須要移項來解出 f[i] 的具體表達式,而移到等式右邊的始終是 q[i+1]*f[i],不妨對 g[i][j] 稍做修改

        令 g[i][j]= j+t

                    +q[i+1]*j  // 在第 i+1 位出錯

                    +p[i+1]*q[i+2]*(f[i+1]+j-1)  // 在第 i+2 位出錯

                    +p[i+1]*p[i+2]*q[i+3]*(f[i+2]+j-2)  // 在第 i+3 位出錯

                    +......

                    +p[i+1]*p[i+2]*p[i+3]*...*q[i+j]*(f[i+j-1]+1)  // 在第 i+j 位出錯

                    +p[i+1]*p[i+2]*p[i+3]*...*p[i+j]*f[i+j]  // 連續打的 k 個字符所有正確

        那麼,咱們就有:f[i]=min{ g[i][j] }/(1-q[i+1])=min{ g[i][j] }/p[i+1],1≤j≤n-i

        初始狀態:f[n]=0

        目標狀態:f[0]

雖然狀態轉移方程推出來了,可是不要急,注意數據範圍:n≤3000

按照上面的式子 DP 的話,這個作法是 n3 的複雜度,還須要作一些優化

咱們觀察 g[i][j]g[i][j+1] 的關係:

         g[i][1]=1+t+q[i+1]+p[i+1]*f[i+1]

        g[i][2]=2+t+q[i+1]*2+p[i+1]*q[i+2]*(f[i+1]+1)+p[i+1]*p[i+2]*f[i+2]

                 =g[i][1]+1+q[i+1]+p[i+1]*p[i+2]*f[i+2]+(p[i+1]*q[i+2]-p[i+1])*f[i+1]+p[i+1]*q[i+2]

                 =g[i][1]+1+q[i+1]+p[i+1]*q[i+2]+p[i+1]*p[i+2]*f[i+2]-p[i+1]*p[i+2]*f[i+1]

                 =g[i][1]+1+1-p[i+1]*p[i+2]+p[i+1]*p[i+2]*f[i+2]-p[i+1]*p[i+2]*f[i+1]

                 =g[i][1]+2+p[i+1]*p[i+2]*(f[i+2]-f[i+1]-1)

同理:g[i][3]=g[i][2]+2+p[i+1]*p[i+2]*p[i+3]*(f[i+3]-f[i+2]-1)

推到這裏,規律已經呼之欲出了。運用這個規律,即可以省去一個循環,把 n3 變成 n2 

 

寫的那麼複雜,其實代碼就幾行...

很是好的一道題目,贊一個!

 

參考代碼

 

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int N=3006;

int n, t;
double p[N], f[N];

int main()
{
    while(scanf("%d%d", &n, &t)!=EOF)
    {
        for(int i=1; i<=n; i++) scanf("%lf", &p[i]), p[i]=1-p[i];
        f[n]=0;
        for(int i=n-1; i>=0; i--)
        {
            double cur=t+1+(1-p[i+1])+p[i+1]*f[i+1];
            double temp=p[i+1];
            f[i]=cur;
            for(int j=2; i+j<=n; j++)
            {
                temp*=p[i+j];
                cur+=2-temp+temp*f[i+j]-temp*f[i+j-1];
                f[i]=min(f[i], cur);
            }
            f[i]/=p[i+1];
        }
        printf("%.8lf\n", f[0]);
    }
    return 0;
}
SGU 422

 

題目鏈接 & AC通道

 

SGU 422 Fast Typing

相關文章
相關標籤/搜索