【51nod 2015】諾德街
題目
題目連結:http://www.51nod.com/Challenge/Problem.html#problemId=2015
又仁慈、又善良、又有錢的夾克老爺買下了一條街!
懂得經商的夾克老爺決定沿街開 \(n\) 個店鋪,從南到北編號為 \(1~n\)。經過緊張的籌備之後,諾德街的 \(n\) 個店鋪同時開張了。由於剛開業,夾克老爺的人手不是非常足夠,所以需要夾克老爺自己去幹活。然而夾克老爺的手下們幹活不積極,使得第 \(i\) 個店鋪在每分鐘都有 \(p_i\) 的概率無人營業,且每分鐘之間相互獨立。於是夾克老爺從 1 號店鋪出發向北走,當遇到第一個無人營業的店鋪時就進去營業而停止移動。如果一直走到第 \(n\)
\(n\leq 10^6\)。
思路
個人認為,這種存在無限種情況的,存在“迴圈”的期望題目,多半是要設答案或中間變數為 \(x\),然後分類討論迴圈與否的貢獻,然後解方程。
發現本題存在迴圈 \(1\to 2\to ...\to n\to (n-1)\to (n-2)\to ...\to 2\),設一次迴圈後仍然沒有結束的期望為 \(s\),若停止則期望走 \(len\) 步,那麼有
\[s=(1-p_1)(1-p_2)...(1-p_n)(1-p_{n-1})...(1-p_2) \]
\[len=\sum^{n}_{i=1}s_i·p_i·(i+1)+\sum^{n-1}_{i=2}s_{2n-i}·p_i·(2n-i-1) \]
可以在 \(O(n)\) 的時間複雜度內求出 \(s\) 和 \(len\)。然後答案 \(ans\) 可能是直接在這一圈停下來 \((len)\),也可能還要走下一圈 \((ans+2n-n)\),其中後者期望為 \(s\)。
所以有
\[ans=s·(ans+2n-2)+len \]
解方程即可解出 \(ans\)。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2000010,MOD=1e9+7; ll n,s,len,ans,a,b,c,p[N]; ll fpow(ll x,int k) { ll ans=1; for (;k;k>>=1,x=x*x%MOD) if (k&1) ans=ans*x%MOD; return ans; } int main() { scanf("%lld%lld%lld%lld%lld",&n,&p[1],&a,&b,&c); for (int i=2;i<=n;i++) p[i]=p[n*2-i]=(a*p[i-1]%MOD*p[i-1]+b*p[i-1]+c)%MOD; s=1; for (int i=1;i<=2*n-2;i++) { len=(len+s*p[i]%MOD*(i-1))%MOD; s=s*(1-p[i])%MOD; } ans=(2LL*n*s%MOD-2*s+len)%MOD*fpow(1-s,MOD-2)%MOD; printf("%lld",(ans%MOD+MOD)%MOD); return 0; }