I.多米诺骨牌 逆元 期望+dp递推

dqs手里共有n个多米诺骨牌,他可以按某种顺序把它们全部摆好。

但是在梦里的dqs并不是非常地熟练,而且这些多米诺骨牌的形状非常奇葩,很难保持平衡。

所以dqs摆第i张骨牌时,有pi 的概率成功,但每当dqs失败时,这个骨牌会把之前摆好的所有骨牌全部推倒。

虽然这看起来非常乏味,但是dqs非常享受摆骨牌的过程!

现在dqs想知道,在最坏的排列下,他将这些骨牌全部摆好时,他所摆骨牌的次数(包括失败的次数和成功的次数)的最大期望。

dqs是个很聪明的人,但是梦里没有电脑,所以他想让你算一算,当然他也不会在摆放骨牌时故意弄倒骨牌。
输入描述

第一行一个整数n,代表牌的数量。

接下来n行,每行两个整数a,b,代表第i张牌摆好的概率为p_i= a/b 。(n≤ 105,1≤ a≤ b≤ 1000 )。

输出描述

每输出一个整数,代表出牌数量的期望对〖10〗^9+7取模的结果。

特别地,设答案化为最简分式后的形式为a/b, 其中a与b互质,输出a*(b对109+7的模逆元),并对结果再次取模。
对于期望累积求和
2
1 2
1 2

6

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;//分子 分母 
const int maxn=1e5+5;
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
//对于pi=3/4这种情况 4次尝试中3次能成功 意味着 4/3次才能达到一次成功 分子分母分开逆元相乘处理 所以为整型 
pll a[maxn];
ll dp[maxn];//dp[i] 前i张牌摆好的期望(平均次数) 
ll pow_mod(ll a,ll b,ll mod)
{
	ll res=1;
	while(b!=0)
	{
		if(b&1)
			res=res*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return res;
}
ll inv_mod(ll a,ll mod)
{
	return pow_mod(a,mod-2,mod);//费马小定理 
}
bool cmp(pll x,pll y)//a1/b1>a2/b2
{
	return x.first*y.second>x.second*y.first;
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].first>>a[i].second;
	}
	sort(a+1,a+n+1,cmp);//最大期望意味着之前失败尽可能少的次数
	dp[0]=0;//0张牌 0次 
	for(int i=1;i<=n;i++)//模拟摆n张牌的过程
	{
		dp[i]=((dp[i-1]+1)*a[i].second%mod*inv_mod(a[i].first,mod))%mod;//*1/p[i]  pi=a/b 1/pi=b/a
	} 
	cout<<dp[n]<<endl;
	return 0;
} 
/*
	dp[i]=(dp[i-1]+1)*1/pi;
	dp[i]代表摆好前i张牌的期望(平均次数)
	pi为本次成功的概率
	1/pi代表尝试1/pi次才能达到一次成功(如 2/3 3次命中2次 1.5次尝试才能达到1次成功
	可理解尝试的最后1次成功 前几次全部失败
对第i张牌来说
	第一次尝试  失败  前i-1张牌摆好dp[i-1]+1(此次失败)
	第二次尝试  失败  dp[i-1]+1
	......
	第1/pi次尝试 成功 dp[i-1]+1(成功)
	
	即1/pi次尝试后成功的总次数 
*/ 

大佬的讲解 立马明白+1意味着此次尝试 失败或者成功 期望即平均次数
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40423146/article/details/88726976