1. 程式人生 > 實用技巧 >【51nod 2015】諾德街

【51nod 2015】諾德街

題目

題目連結:http://www.51nod.com/Challenge/Problem.html#problemId=2015
又仁慈、又善良、又有錢的夾克老爺買下了一條街!
懂得經商的夾克老爺決定沿街開 \(n\) 個店鋪,從南到北編號為 \(1~n\)。經過緊張的籌備之後,諾德街的 \(n\) 個店鋪同時開張了。由於剛開業,夾克老爺的人手不是非常足夠,所以需要夾克老爺自己去幹活。然而夾克老爺的手下們幹活不積極,使得第 \(i\) 個店鋪在每分鐘都有 \(p_i\) 的概率無人營業,且每分鐘之間相互獨立。於是夾克老爺從 1 號店鋪出發向北走,當遇到第一個無人營業的店鋪時就進去營業而停止移動。如果一直走到第 \(n\)

個店鋪都有人營業,則原路返回,然後不停地來回走直到遇到一個無人營業的店鋪為止。現在夾克老爺想知道,自己期望走多少分鐘。假設夾克老爺從一個店鋪到下一個店鋪需要 1 分鐘。
\(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;
}