题意:
你试图把一些多米诺骨牌排成直线,然后推倒它们。但是如果你在放骨牌的时候不小心把刚放的骨牌碰倒了,它就会把相临的一串骨牌全都碰倒,而你的工作也被部分的破坏了。 比如你已经把骨牌摆成了DD__DxDDD_D的形状,而想要在x这个位置再放一块骨牌。它可能会把左边的一块骨牌或右边的三块骨牌碰倒,而你将不得不重新摆放这些骨牌。 这种失误是无法避免的,但是你可以应用一种特殊的放骨牌方法来使骨牌更多的向一个方向倒下。 给出你要摆放的骨牌数目,以及放骨牌时它向左和向右倒的概率,计算你为完成任务摆放的骨牌数目的平均数。假设你使用了最佳的摆放策略。
输入将包含至多100个测试点,每个测试点占一行,包含需要摆放的骨牌数目n (1≤n≤1000),以及两个非负实数Pl, Pr,表示骨牌向左和向右倒的概率。保证1<Pl+Pr≤0.5。 最后一个测试点包含一个数0。对于每个测试点输出题目要求的数目,保留两位小数。
首先把最后一个放在i,根据期望
l=i-1,r=n-1-i
E[n]=(1+pl*E[l]+pr*E[r])/(1-pl-pr)+E[l]+E[r]
1/(1-pl-pr)表示成功要多少步
E[i]表示长为i的连续方块
E[i]=(1+pl*E[j]+pr*E[i-1-j])/(1-pl-pr)+E[j]+E[i-1-j]
O(n^2)DP就行了
不过有加强版(n<=10^5)
似乎这个j的选择有下凸性,所以可以O(n)
但不知道怎麽证
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 double f[1001],pl,pr; 8 int n; 9 double cal(int i,int L) 10 { 11 int R=i-1-L; 12 return (1+pl*f[L]+pr*f[R])/(1-pl-pr)+f[L]+f[R]; 13 } 14 int main() 15 {int i,j; 16 while (cin>>n&&n) 17 { 18 scanf("%lf%lf",&pl,&pr); 19 for (i=1;i<=n;i++) 20 f[i]=10000000.0; 21 f[0]=0; 22 for (i=1;i<=n;i++) 23 { 24 for (j=0;j<=i-1;j++) 25 { 26 f[i]=min(f[i],cal(i,j)); 27 } 28 } 29 printf("%.2lf ",f[n]); 30 } 31 }