两个线段一左一右,题目保证了l[i-1]<=l[i] r[i-1]<=r[i]
则只会出现相交一段,或相离2种情况。
分情况讨论把分别的期望算出来。对于两段:
第一种:相离:为了方便书写我们用[a,b][c,d]表示:
显然
第二种 相交:如下所示
此时:对于ab这条线段
当a<=y<=c时,
当c<=y<=b时,
对于x,b<=x<=d时
对于x,c<=x<=b时
f(x),f(y)时概率密度函数,由于x,y服从均匀分布所以
去掉绝对值后,解这个二重积分可得:
把上面三个期望求和即相交的总期望。
相离时的期望:
发现只有后面不同,把后面那个式子分子分解,枚举i,找到所有j使得j<i,且i与j的线段相交。
利用前缀和即可快速算出。
这里直接贴下别人的题解里的图片。markdown打的太慢了。。
这题精度要求比较高 用long double 保险。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double eps=1e-6;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
db l[M],r[M];
db len[M];
db s1[M];//(lj+rj)/2 前缀和
db s2[M];//1/(rj-lj) 前缀和
db s3[M];//rj^3/(rj-lj)前缀和
db s4[M];//rj^2/(rj-lj) 前缀和
db s5[M];//rj/(rj-lj) 前缀和
int main()
{
freopen("30.in","r",stdin);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%Lf%Lf",&l[i],&r[i]);
len[i]=r[i]-l[i];
s1[i]=s1[i-1]+(l[i]+r[i])/2;
if(fabs(len[i])<=eps)
{
s2[i]=s2[i-1];s3[i]=s3[i-1];s4[i]=s4[i-1];s5[i]=s5[i-1];
continue;
}
// cout<<len[i]<<endl;
db t=1.0;
s2[i]=s2[i-1]+t/len[i];
t*=r[i];s3[i]=s3[i-1]+t/len[i];
t*=r[i];s4[i]=s4[i-1]+t/len[i];
t*=r[i];s5[i]=s5[i-1]+t/len[i];
}
db ans=0;
for(int i=1;i<=n;i++)
{
ans+=1.0*(i-1)*(l[i]+r[i])/2-s1[i-1];
if(fabs(len[i])<eps)continue;
int p=upper_bound(r+1,r+n+1,l[i])-r;
db m2=(s2[i-1]-s2[p-1]),m3=(s3[i-1]-s3[p-1]),m4=(s4[i-1]-s4[p-1]),m5=(s5[i-1]-s5[p-1]);
db tp=1.0;
// cout<<ans<<"- "<<endl;
ans+=tp/len[i]*m5/3;tp*=l[i];
ans-=tp/len[i]*m4;tp*=l[i];
ans+=tp/len[i]*m3;tp*=l[i];
ans-=tp/len[i]*m2/3;
// cout<<i<<" "<<p<<" "<<ans<<" "<<(l[i]+r[i])/2<<" "<<s1[i-1]<<endl;
}
ans=ans/n/n;
printf("%.10Lf\n",ans);
return 0;
}