【JSOI2015】非诚勿扰

来源:互联网 发布:java compareto返回值 编辑:程序博客网 时间:2024/05/01 19:10

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

5 5
0.5
5 1
3 2
2 2
2 1
3 1

Sample Output

0.89

Solution

设f[i,j]表示第i个女选择第j个男的概率
设这个男的在这个女的中排名第r,这个女的的如意郎君列表长度为l
那么第一轮选中的概率是(1p)(r1)p
第二轮是(1p)(r1)p(1p)l
第三轮是(1p)(r1)p(1p)2l
第n轮是(1p)(r1)p(1p)(n1)l
这是一个等比数列!!!!
用公式求和,得

(1p)(r1)p(1(1p)nl)1(1p)l

n
因为1p<0
所以(1(1p)nl)0
所以概率为
(1p)(r1)p1(1p)l

f[i,j]就可以O(1)做了
那么答案就是f[i,j]f[k,l](k>i,l<j)
这样直接枚举可以得30分
可以考虑优化
因为有值的f只有m个,那么只枚举这m个f
先将i从大到小枚举,这是为了保证k>l这个条件
然后枚举i这个女的的所有的男的,也就是j,在树状数组中查询1~j中的和就是答案
然后把f[i, ]加入树状数组
时间复杂度O(mlog2(n))

Code

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define db double#define N 501000using namespace std;int n,m,l[N],last[N],next[N],to[N],tot,b[N];db p,t[N];struct node{    int x,y;}a[N];void putin(int x,int y){    next[++tot]=last[x];last[x]=tot;to[tot]=y;}db mi(db a,int b){    if(b==0) return 1;    if(b==1) return a;    db k=mi(a,b/2);    k=k*k;    if(b%2==1) k*=a;    return k;}int lowbit(int a){return a&(-a);}void insert(int x,db z){    for(;x<=n;x+=lowbit(x)) t[x]+=z;}db get(int x){    db ans=0;    for(;x;x-=lowbit(x)) ans+=t[x];    return ans;}int main(){    freopen("cross.in","r",stdin);    freopen("cross.out","w",stdout);    scanf("%d%d",&n,&m);    scanf("%lf",&p);    fo(i,1,m)    {        int x,y;scanf("%d%d",&x,&y);        putin(x,y);l[x]++;    }    db ans=0;    fd(i,n,1)    {        b[0]=0;        for(int k=last[i];k;k=next[k]) b[++b[0]]=to[k];        if(b[0]==0) continue;        sort(b+1,b+b[0]+1);        fo(j,1,b[0])        {            db jy=mi((1-p),j-1)*p/(1-mi(1-p,l[i]));            ans+=jy*get(b[j]-1);        }        fo(j,1,b[0])        {            db jy=mi((1-p),j-1)*p/(1-mi(1-p,l[i]));            insert(b[j],jy);        }    }    printf("%.2lf",ans);}
1 0