BZOJ4481 JSOI2015非诚勿扰(概率期望+树状数组)
首先求出每个女性接受某个男性的概率。这个概率显然是一个无穷等比数列求和。
然后按编号从小到大考虑每个女性,维护出每个男性被选择的期望次数,BIT上查询后缀和即可。
需要long double。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 500010 #define double long double int n,m; double p,tree[N],q[N],ans; vector<int> a[N]; double query(int k){double s=0;while (k) s+=tree[k],k-=k&-k;return s;} void ins(int k,double s){while (k<=n) tree[k]+=s,k+=k&-k;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj4481.in","r",stdin); freopen("bzoj4481.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read();cin>>p; for (int i=1;i<=m;i++) { int x=read(),y=read(); a[x].push_back(y); } int cnt=0; for (int i=1;i<=n;i++) { sort(a[i].begin(),a[i].end()); int s=a[i].size(); double v=1; for (int j=0;j<s;j++) q[j]=v*p,v*=1-p; for (int j=0;j<s;j++) q[j]/=1-v; for (int j=0;j<s;j++) ans+=q[j]*(cnt-query(a[i][j])); for (int j=0;j<s;j++) ins(a[i][j],q[j]); cnt+=s>0; } #undef double double p=ans;printf("%.2f",p); return 0; }