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意味着此次尝试 失败或者成功 期望即平均次数