bzoj 4481 [Jsoi2015]非诚勿扰

4481: [Jsoi2015]非诚勿扰
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 147 Solved: 75
[Submit][Status][Discuss]
Description

【故事背景】
JYY赶上了互联网创业的大潮,为非常勿扰开发了最新的手机App实现单身
大龄青年之间的“速配”。然而随着用户数量的增长,JYY发现现有速配的算法似
乎很难满足大家的要求,因此JYY决定请你来调查一下其中的原因。
【问题描述】
应用的后台一共有N个女性和M个男性,他们每个人都希望能够找到自己的
合适伴侣。为了方便,每个男性都被编上了1到N之间的一个号码,并且任意两
个人的号码不一样。每个女性也被如此编号。
JYY应用的最大特点是赋予女性较高的选择权,让每个女性指定自己的“如
意郎君列表”。每个女性的如意郎君列表都是所有男性的一个子集,并且可能为
空。如果列表非空,她们会在其中选择一个男性作为自己最终接受的对象。
JYY用如下算法来为每个女性速配最终接受的男性:将“如意郎君列表”中的
男性按照编号从小到大的顺序呈现给她。对于每次呈现,她将独立地以P的概率
接受这个男性(换言之,会以1−P的概率拒绝这个男性)。如果她选择了拒绝,
App就会呈现列表中下一个男性,以此类推。如果列表中所有的男性都已经呈现,
那么中介所会重新按照列表的顺序来呈现这些男性,直到她接受了某个男性为止。
显然,在这种规则下,每个女性只能选择接受一个男性,而一个男性可能被多个
女性所接受。当然,也可能有部分男性不被任何一个女性接受。
这样,每个女性就有了自己接受的男性(“如意郎君列表”为空的除外)。现
在考虑任意两个不同的、如意郎君列表非空的女性a和b,如果a的编号比b的编
号小,而a选择的男性的编号比b选择的编号大,那么女性a和女性b就叫做一对
不稳定因素。
由于每个女性选择的男性是有一定的随机性的,所以不稳定因素的数目也是
有一定随机性的。JYY希望你能够求得不稳定因素的期望个数(即平均数目),
从而进一步研究为什么速配算法不能满足大家的需求。

Input

输入第一行包含2个自然数N,M,表示有N个女性和N个男性,以及所有女
性的“如意郎君列表”长度之和是M。
接下来一行一个实数P,为女性接受男性的概率。
接下来M行,每行包含两个整数a,b,表示男性b在女性a的“如意郎君列表”
中。
输入保证每个女性的“如意郎君列表”中的男性出现切仅出现一次。
1≤N,M≤500,000,0.4≤P<0.6

Output

输出1行,包含一个实数,四舍五入后保留到小数点后2位,表示不稳定因素的期望数目。

Sample Input

5 5

0.5

5 1

3 2

2 2

2 1

3 1

Sample Output

0.89

HINT

Source

By 佚名上传


【分析】
数学期望+树状数组。
首先计算每一对男女选中的概率
枚举每一个女的,发现在第一轮中,编号从小到大的男的的选中概率为

pp(1p)p(1p) 2 ...p(1p) k1  

第二轮

p(1p) k p(1p) k+1 ......p(1p) 2k1  

相信聪明的你一定发现了什么规律
在任意一轮中,编号从小到大男生选中概率的比值均为
p:(1p):(1p) 2 ::(1p) k  

那我们把第一轮的概率 pp(1p)p(1p) 2 ...p(1p) k1   加起来记为q,那么每个男生被选中的概率即为 p(1p) num1 /q  (num为男生对于该女生的编号排第几)

然后树状数组搞一下…ok

注意一下这题还要用long double…OTZ


【代码】

//bzoj 4481 [Jsoi2015]非诚勿扰
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define double long double
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=500005;
int n,m;
double p,ans;
double c[mxn];
struct node {int x,y;} a[mxn];
inline bool comp(node u,node v)
{
    return u.x==v.x?u.y<v.y:u.x<v.x;
}
inline int lowbit(int x)
{
    return x&-x;
}
inline void add(int x,double v)
{
    for(int i=x;i<=n;i+=lowbit(i))
      c[i]+=v;
}
inline double getsum(int x)
{
    double sum=0;
    for(int i=x;i;i-=lowbit(i))
      sum+=c[i];
    return sum;
}
int main()
{
    int i,j,last;
    scanf("%d%d%Lf",&n,&m,&p);
    fo(i,1,m) scanf("%d%d",&a[i].x,&a[i].y);
    sort(a+1,a+m+1,comp);
    for(i=1;i<=m;i=last+1)
    {
        double q=1;last=i;
        while(a[last+1].x==a[last].x) last++;
        fo(j,1,last-i+1) q=q*(1-p);q=1-q;
        double up=p;
        fo(j,i,last)
        {
            if(j>i) up=up*(1-p);
            double now=up/q;
            add(n-a[j].y+1,now);
            ans+=now*getsum(n-a[j].y);
        }
    }
    printf("%.2Lf\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值