codeforces908d(概率、期望)

D. New Year and Arbitrary Arrangement
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given three integers kpa and pb.

You will construct a sequence with the following algorithm: Initially, start with the empty sequence. Each second, you do the following. With probability pa / (pa + pb), add 'a' to the end of the sequence. Otherwise (with probability pb / (pa + pb)), add 'b' to the end of the sequence.

You stop once there are at least k subsequences that form 'ab'. Determine the expected number of times 'ab' is a subsequence in the resulting sequence. It can be shown that this can be represented by P / Q, where P and Q are coprime integers, and . Print the value of .

Input

The first line will contain three integers integer k, pa, pb (1 ≤ k ≤ 1 0001 ≤ pa, pb ≤ 1 000 000).

Output

Print a single integer, the answer to the problem.

Examples
input
1 1 1
output
2
input
3 1 4
output
370000006
Note

The first sample, we will keep appending to our sequence until we get the subsequence 'ab' at least once. For instance, we get the sequence 'ab' with probability 1/4, 'bbab' with probability 1/16, and 'aab' with probability 1/8. Note, it's impossible for us to end with a sequence like 'aabab', since we would have stopped our algorithm once we had the prefix 'aab'.

The expected amount of times that 'ab' will occur across all valid sequences is 2.

For the second sample, the answer is equal to .



/*
题意:从一个空串开始每次在串的末尾添加a或b,几率分别为pa和pb,而一旦在整个串中产生了k个及以上的'ab'子序列(a、b可以分开),
操作就会停止,现在需要求结束后串中'ab'序列总个数的期望
思路:看了网上各路大神的思路才懂了一点点。
把不断增长串的过程看成是树,每个节点后面都有两个分叉,即为后一位添加a或b,在每个节点中储存的就是从这个节点这个状态开始
向后添加a、b所得到的'ab'序列总个数的期望,这样从所有最末的状态(达到k个'ab'子序列)就可以递推到最初的状态(即空串)的期望
结果。 
令dp[i][j]表示前缀包含i个a,j个ab子串的所有字符串,得到的期望ab子串个数。
转移: 
在此前缀后添上a:dp[i][j]+=dp[i+1][j]*Pa/(Pa+Pb) 
在此前缀后添上b:dp[i][j]+=dp[i][j+i]*Pb/(Pa+Pb) 
初始状态:dp[i][j]=j (j≥k) 
目标状态:dp[0][0](无前缀,代表所有串) 
然而由于有些无穷的情况(有无穷多a),所以这是不可行的。
但是考虑dp[i][j](i+j≥k) ,可以先把这个的期望通过数学方法算出来,继而在通过递归算出目标情况。
这种情况下,只有后面出现一个b就会立即停止操作。
设它后面添加的串中'ab'序列个数为ans,P=pb/(pa+pb)则:
ans=(1-P)*P*1+((1-P)^2)*P*2+((1-P)^3)*P*3+...
计算得ans=pa/pb
则dp[i][j]=i+j+pa/pb
此外,由于最终序列中必然有至少一个a,目标状态可以使用dp[1][0]
分数取模:
(a/b)%m=(a*b^(m-2))%m 
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define maxk 1010
#define MOD 1000000007
typedef __int64 LL;
LL k,pa,pb;
LL dp[maxk][maxk];
LL quick_pow(LL x,LL p)
{
	LL ans=1;
	while(p)
	{
		if(p&1)ans=(ans*x)%MOD;
		p>>=1;
		x=(x*x)%MOD;
	}
	return ans;
}
LL DP(int i,int j)
{
	if(i+j>=k)
	{
		return (i+j+(pa*quick_pow(pb,MOD-2))%MOD)%MOD;
	}
	if(dp[i][j]!=-1)
	{
		return dp[i][j];
	}
	return dp[i][j]=(((pa*DP(i+1,j))%MOD+(pb*DP(i,i+j))%MOD)*quick_pow(pa+pb,MOD-2))%MOD;
}
int main()
{
	while(~scanf("%I64d%I64d%I64d",&k,&pa,&pb))
	{
		memset(dp,-1,sizeof(dp));
		printf("%I64d\n",DP(1,0));
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值