题解:P6089 [JSOI2015] 非诚勿扰

分析

首先我们要求出对于第 i 位女性,她选择每个列表中的男性的概率是多少。

第一轮选择第一位的概率为 p,选择第二位的概率为 p(1p),以此类推。

显然第一轮选择第 k 位的概率为 p(1p)k1

假设列表中有 n 名男性,那么第二轮选择第一位的概率为 p(1p)n

所以选择第一位的概率 P1 为:

P1=i=0p(1p)ni(1p)P1=i=1p(1p)ni

上下两式相减,得到:

(1(1p)n)P1=i=0p(1p)nii=1p(1p)ni(1(1p)n)P1=pP1=p1(1p)n

这样我们就搞定了 P1

显然有:Pi=(1p)Pi1

我们已经对于每个女性求出选择每个男性的概率,现在要考虑如何求得答案。

Si 为第 i 个女性可选择的男性的集合。

答案就是下式:

i=1nbSij=1i1k=b+1nP(j  k)P(i  b)

考虑从小到大枚举女性,这样就保证了后枚举的女性编号一定大于枚举过的。

我们可以维护一个序列,存储选择第 b 个男性的期望人数。

每次枚举 ib,对答案的贡献就是 [b+1,n] 这个区间内的期望人数。

在枚举完一个 i 后,将自己选择每个男性的概率累加到序列上。

单点修改,区间查询,用树状数组维护。

时间复杂度 O(mlogm)

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
typedef long double f64_t;
struct BIT:vector<f64_t>
{
using vector::vector;
void modify(int p, f64_t x) {for(;p<size();p+=p&-p) at(p)+=x;}
f64_t query(int p) {f64_t r=0;for(;p;p-=p&-p) r+=at(p);return r;}
};
BIT ta(maxn);
vector<int> al[maxn];
int main()
{
int n, m;
f64_t p, ans=0;
cin>>n>>m>>p;
for(int a, b;m--;)
cin>>a>>b, al[a].emplace_back(b);
for(int i=1;i<=n;i++)
{
if(al[i].empty()) continue;
sort(al[i].begin(), al[i].end());
for(f64_t px=p/(1-pow(1-p, al[i].size()));auto b:al[i])
ans+=(ta.query(n)-ta.query(b))*px,
ta.modify(b, px), px*=1-p;
}
cout<<format("{:.2f}", ans);
}

本文作者:redacted-area

本文链接:https://www.cnblogs.com/redacted-area/p/18405328

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起