hihocoder1489 Legendary Items (微軟2017年預科生計劃在線編程筆試)
http://hihocoder.com/problemset/problem/1489
筆試題第一道,雖然說第一道都很水,但是我感覺這題不算特別水把。。這道題我就卡住了我記得,tle,最後只有30分,比較慘烈。我個人感覺這道題正解比較難想把,那時候太年輕,沒有想到當item很大時,可以從第八道item開始就把初始p當成0來計算。。不過我試了一下,發現即使如此,還要計算每次的數學期望,反正我當時要是不知道,Ei和Ei+1之間的聯系,應該還是算不出來。。我太麻瓜了。。
貼一下我tle代碼,思路就是dfs這個概率樹。。非常完美可惜不行。
#include <iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<cmath> using namespace std; double startp,q; int n; double getsum(int all,int num,double p,double sum) { double left,right; if(num==n) return sum*all; if(p>=1) { right=0; double nextp; if(num>=7) nextp=0; else nextp=startp/(1<<(num+1)); left=getsum(all+1,num+1,nextp,sum); } else if(p==0) { left=0; right=getsum(all+1,num,q,sum); } else { right=getsum(all+1,num,p+q,sum*(1-p));double nextp; if(num>=8) nextp=0; else nextp=startp/(1<<(num+1)); left=getsum(all+1,num+1,nextp,sum*p); } return left +right; } int main() { double res; scanf("%lf %lf %d",&startp,&q,&n); startp/=100; q/=100; res=getsum(0,0,startp,1); printf("%.2lf\n",res); return 0; }
這題很關鍵的一點的就是,就是不同個數的期望是可以相加的。這個地方我一直很不明白,非常困惑,哇,要是我知道是這樣,就直接相加了啊,誰還寫dfs啊。。
http://www.mamicode.com/info-detail-1759090.html 這個我看了這個博主給的解釋:
其實我們發現圖中那兩個標號 1 的節點子樹是一樣的,它們獲取下一個物品的情況和期望都是一樣的。我本來在考慮不同情況下拿到第一個,開始拿第二個,第二個和第一個是不是獨立的?但是其實所有情況下拿到第一個的概率總和是1,所以無論 dfs 的哪一個分支,最後都會到同一個初始概率去獲取第二個,所以獲取第二個的期望與第一個是獨立可加的。
我比較愚鈍,還是不能非常理解。。相互獨立的話,可是題意中給的式子是
2*50%*25% + 3*50%*75%*100% + 3*50%*100%*25% + 4*50%*100%*75%*100% = 3.25
意思是每個都是和做掉的任務個數是相關的,並且是累加的。。就是完成了1件傳說後,已經完成了2個任務,然後下次就要從3開始算,並且概率還要相乘。。算的話看起來好像不是直接相加就好了。。當然博主說的很好也是對的。。只是我乍一看並不是非常理解。。
http://blog.csdn.net/sddyzjh/article/details/68950610 還有這個博主,
那麽期望的計算式可以寫成Ei=Σpk?lk,其中pk表示做了lk個任務後拿到i個獎勵的概率
用Pi表示?P2i?%
接著考慮Ei+1=Σp′k?l′k
=Pi+1?Σpk?(lk+1)
+(1?Pi+1)?(Pi+1+Q%)?Σpk?(lk+2)
+(1?Pi+1)?(1?Pi+1?Q%)?(Pi+1+2Q%)?Σpk?(lk+3)+...
直到Pi+1+kQ%超過1結束
於是用ci=Σpk
Ei+1=Σp′k?l′k
=Pi+1?(Ei+ci)
+(1?Pi+1)?(Pi+1+Q%)?(Ei+2ci)
+(1?Pi+1)?(1?Pi+1?Q%)?(Pi+1+2Q%)?(Ei+3ci)+...
直接用算的,求出Ei+1和Ei的關系,答案就很明顯了。看了式子之後,發覺寫的很好,很容易理解。應該可以根據這個規律直接code,博主給的代碼也蠻好理解的。
其實有一個很明顯的地方值得註意。其實我們可以發現Ei=Σpk?lk跟概率論的數學期望很相似啊。這道題其實就是讓我們求數學期望,我之前一直不知道在想什麽,把繞來繞去。。我們可以發現Ei是絕對收斂的呀。要是k無限大,就是完成的任務無限多的時候,概率是趨於1的呀講道理啊,就是完成任務無限多,不是肯定要完成傳說任務的。
數學期望其實就是一個加權平均意思,這道題中的意思就是當給定了n,即要完成n個傳說任務,加權平均一下,數學期望在這裏表示的就是要完成平均多少個任務才能完成n個傳說任務。數學期望在物理上就是一堆質點的重心,也就是加權平均。兩個鐵塊已知重心的話,把他們重疊起來,在坐標軸上新的重心不就是兩個重心的中點嘛,所以是可以直接相加的。
設C為一個常數,X和Y是兩個隨機變量。以下是數學期望的重要性質: 1.E(C)=C 2.E(CX)=CE(X) 3.E(X+Y)=E(X)+E(Y) 4.當X和Y相互獨立時,E(XY)=E(X)E(Y) 性質3和性質4可以推到到任意有限個相互獨立的隨機變量之和或之積的情況。上面是數學期望的性質,是可以直接相加的兩個期望。所以這道題也不難理解了。 這是數學期望期望E(X+Y)=E(X)+E(Y) 就是這道題的精髓,很特別,我開始不知道這個,就被dfs套牢了。。唉。悲傷的故事。。 數學果然是算法的靈魂。。好好學習。。天天向上。。 貼一下別人ac代碼。。
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; const int maxn=1e6+5; const int INF=0x3f3f3f3f; double ans=0; double num[105] = {0}; int n,p,q; int main() { scanf("%d%d%d",&p,&q,&n); for(int pre = 0 ; pre <= 100 ; ++ pre ) { int cnt = 0; double p1 = 1; while(1) { double xq = ( pre + cnt * q) / 100.0; if( pre + cnt * q >= 100 ) { num[pre] += ( cnt + 1 ) * p1 ; break; } num[pre] += p1 * xq * ( cnt + 1 ); p1 *= ( 1 - xq ); cnt++; } } int pre = p; for(int i = 1 ; i <= n ; ++ i ) { if( pre == 0 ) { ans += ( n - i + 1 ) * num[0]; break; } ans += num[pre]; pre >>= 1; } printf("%.2lf\n",ans); return 0; }
hihocoder1489 Legendary Items (微軟2017年預科生計劃在線編程筆試)