• [JSOI2015]非诚勿扰


    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
    假设第i个女性,匹配第j个男性,总共有k个可以匹配
    p(i,j)=(1-p)j-1*p+(1-p)k*(1-p)j-1*p+......
    套用等比求和:
    S=A(1-qn)/(1-q)
    因为n为无穷大,所以qn≈0
    所以S≈A/(1-q)
    这里A=(1-p)j-1*p,q=(1-p)k
    求出每条匹配边的概率,然后倒序处理
    从后往前处理一个女性i,枚举指向v边,查w(i,v)*(i+1~n,1~v-1)的概率和
    显然可以树状数组,先查询比v小的概率和,再把每条边的概率插入
    复杂度O(mlogn)
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct ZYYS
     8 {
     9   int u,v;
    10   double d;
    11 }e[500001];
    12 struct Node
    13 {
    14   int next,to;
    15   double dis;
    16 }edge[500001];
    17 double ans,p,c[500001];
    18 int num,head[500001],n,m,du[500001],l[500001];
    19 bool cmp(ZYYS a,ZYYS b)
    20 {
    21   if (a.u==b.u) return a.v<b.v;
    22   return a.u>b.u;
    23 }
    24 double qpow(double x,int y)
    25 {
    26   double res=1.0;
    27   while (y)
    28     {
    29       if (y&1) res=res*x;
    30       x=x*x;
    31       y/=2;
    32     }
    33   return res;
    34 }
    35 void add(int u,int v,double d)
    36 {
    37   num++;
    38   edge[num].next=head[u];
    39   head[u]=num;
    40   edge[num].to=v;
    41   edge[num].dis=d;
    42 }
    43 void update(int x,double d)
    44 {
    45   while (x<=n)
    46     {
    47       c[x]+=d;
    48       x+=(x&(-x));
    49     }
    50 }
    51 double query(int x)
    52 {
    53   double s=0;
    54   while (x)
    55     {
    56       s+=c[x];
    57       x-=(x&(-x));
    58     }
    59   return s;
    60 }
    61 int main()
    62 {int i,u,v,j;
    63   cin>>n>>m;
    64   cin>>p;
    65   for (i=1;i<=m;i++)
    66     {
    67       scanf("%d%d",&u,&v);
    68       e[i].u=u;e[i].v=v;
    69       du[u]++;
    70     }
    71   sort(e+1,e+m+1,cmp);
    72   for (i=1;i<=m;i++)
    73     {
    74       l[e[i].u]++;
    75       e[i].d=qpow(1-p,l[e[i].u]-1)*p;
    76       e[i].d/=1-qpow(1-p,du[e[i].u]);
    77       add(e[i].u,e[i].v,e[i].d);
    78     }
    79   for (i=n;i>=1;i--)
    80     {
    81       for (j=head[i];j;j=edge[j].next)
    82     {
    83       int v=edge[j].to;
    84       ans+=edge[j].dis*query(v-1);
    85     }
    86       for (j=head[i];j;j=edge[j].next)
    87     {
    88       int v=edge[j].to;
    89       update(v,edge[j].dis);
    90     }
    91     }
    92   printf("%.2lf
    ",ans);
    93 }
  • 相关阅读:
    Excel表格函数逻辑排错
    MobaXterm体验最好的SSH客户端
    Excel中的常用函数
    Shell 知识点2020
    Linux 知识点2020
    Python知识点2020
    es6 模版字符串
    es6对象定义简写
    es6解构赋值
    ES6 let const关键字
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8315596.html
Copyright © 2020-2023  润新知