题目链接:点击打开链接
题目:
题意:
现在有一场比赛,有n个人,每个人有一个分数。从n个人中随意抽两个人出来(一个人的分数比另一个的大),分数少的人赢了比赛后获得s分后,分数超过了原来分数较大的人,即一种符合要求的情况。每个人输的概率为p[i]。问所有满足要求的情况的期望和。
思路:
对每一个人,求[score[i], score[i]-s) 区间内的期望和。二分求得score[i]-s,设下标为r。求期望即求和p[i] * (1-p[j]), (j from i to r)。
注意的是,题目只给了0.5秒。求下标r,求的是离score[i]-s(左闭右开,即大于score[i]-s)最近的那个人的下标。此外,题目中表明当两个人的分数相同时,可以不用考虑,那么对当前的这个人,我们要找到离他最远的,和他分数相同的那个人的下标。同时处理一个1-p[j]的前缀和,避免重复计算。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
int a[MAXN], n, s;
double p[MAXN], ans=0;
double pre[MAXN];
int main(){
scanf("%d%d", &n, &s);
for(int i=0; i<n; ++i) scanf("%d", &a[i]);
for(int i=0; i<n; ++i) scanf("%lf", &p[i]);
for(int i=0; i<n; ++i){
pre[i+1] = pre[i] + (1-p[i]);
}
for(int i=0; i<n; ++i){
int key = a[i]-s, l=i+1, r=n-1, mid;
while(l<=r){
mid = (l+r)>>1;
if(a[mid] > key)
l = mid+1;
else
r = mid-1;
}
if(a[r]==key) r-=1;
int ll=i+1, rr=n-1, mm;
while(ll<=rr){
mm = (ll+rr)>>1;
if(a[mm] >= a[i])
ll = mm+1;
else
rr = mm-1;
}
ans += p[i]*(pre[r+1]-pre[rr+1]);
}
printf("%.9lf\n", ans);
return 0;
}