天天看点

【JSOI2015】【JZOJ 4063】非诚勿扰DescriptionAnalysisCode

Description

【JSOI2015】【JZOJ 4063】非诚勿扰DescriptionAnalysisCode
【JSOI2015】【JZOJ 4063】非诚勿扰DescriptionAnalysisCode

Analysis

对于每个女性,开一个vector记录可选的男性

扫一遍,可以O(1)算出该女性选择第i个男性的期望(推推公式发现是等比数列)

有了这个就好办啦,按女性为第一关键字男性第二关键字排个序,用树状数组记录下前面的女性选择比当前大的男性的概率和

O(nlogn)

在算期望时涉及除法运算,精度误差较大,所以要开long double或者强行不用等比数列直接乘多几次

Code

#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long double db;
const int N=;
db P,BIT[N];
int n,m,num;
vector<int> a[N];
struct node
{
    int x,y;
    db p;
}b[N];
bool cmp(node a,node b)
{
    return a.x<b.x || a.x==b.x && a.y<b.y;
}
int lowbit(int x)
{
    return x&-x;
}
db get(int x)
{
    db t=;
    for(int i=x;i;i-=lowbit(i)) t+=BIT[i];
    return t;
}
void add(int x,db y)
{
    for(int i=x;i<=n;i+=lowbit(i)) BIT[i]+=y;
}
int main()
{
    freopen("cross.in","r",stdin);
    freopen("cross.out","w",stdout);
    int x,y;
    scanf("%d %d %Lf",&n,&m,&P);
    fo(i,,m)
    {
        scanf("%d %d",&x,&y);
        a[x].push_back(y);
    }
    fo(i,,n)
    {
        int s=a[i].size();
        sort(a[i].begin(),a[i].end());
        fo(id,,s-)
        {
            int j=a[i][id];
            b[++num].x=i,b[num].y=j;
            db t1=pow(-P,id)*P,t2=-pow(-P,s);
            b[num].p=t1/t2;
        }
    }
    sort(b+,b+num+,cmp);
    db ans=;
    fo(i,,num)
    {
        db t=get(n)-get(b[i].y);
        ans+=b[i].p*t;
        add(b[i].y,b[i].p);
    }
    printf("%.2Lf",ans);
    return ;
}