。。。。
求的是 期望嘛。。。
range[i]=R[i]-L[i]+1
我们设【l,r】之间,p的倍数的个数为tm[i],
那么每一对 i,i+1他们每场 赢钱的 概率是 pi=【tm[i]*range[i+1]+tm[i+1]*range[i]-tm[i]*tm[i+1] 】 / (range[i]*rangr[i+1])
而他们 每次赢钱是 2个人各得一千,也就是pi*2000;
所以for (i=1;i<=n;i++ ) ans+= pi*2000 ; 便是答案;
至于如何计算【l,r】之间p的倍数,比赛的时候想的办法比较蠢。 先二分找到第一个大于等于l的倍数,再二分找到第一个大于等于R的倍数,两者相减+1便是 p的倍数的个数了 (边界特判)
后来发现还可以这样算 o(1): (别人的代码)
int get_cnt(int x, int y){
if(x % p == 0) return (y - x) / p + 1;
int t = p - x % p + x;
if(y < t) return 0;
return (y - t) / p + 1;
}
先判断如果x是p的倍数,那么 (y-x)/p+1便是答案
否则,求出x之后的第一个p的倍数,也就是t,然后如果t>Y 表示区间不存在p的倍数,否则就转为前面的情况了(y-t)/p+1为答案
比赛的代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include<stack>
using namespace std;
__int64 L[100005];//副对角线元素之和
__int64 R[100005]; //主对角线元素之和
__int64 tm[100005];
__int64 range[100005];
__int64 n,p;
__int64 solve(__int64 x )
{
__int64 l=0;
__int64 r=1000000000;
__int64 mid;
while(l<=r)
{
if (r-l<=1)
{
if (l*p>=x)
return l;
else
{
if (r*p>=x)
return r;
}
}
mid=(l+r)/2;
if (mid*p>=x)
r=mid;
else
l=mid+1;
}
}
int main()
{
__int64 i,x,y;
scanf("%I64d%I64d",&n,&p);
for (i=1;i<=n;i++)
{
scanf("%I64d%I64d",&L[i],&R[i]);
range[i]=R[i]-L[i]+1;
__int64 ret1=solve(L[i]);
__int64 ret2=solve(R[i]);
if (ret2*p!=R[i])
ret2--;
tm[i]=ret2-ret1+1;
}
double ans=0;
double upsum=0;
double downsum=0;
for (i=1;i<=n-1;i++)
{
upsum=tm[i]*range[i+1]+ tm[i+1]*range[i]- tm[i]*tm[i+1];
downsum=range[i]*range[i+1];
ans+=upsum*2000/downsum;
}
upsum=tm[1]*range[n]+ tm[n]*range[1]- tm[1]*tm[n];
downsum=range[1]*range[n];
ans+=upsum*2000/downsum;
printf("%.6lf\n" ,ans);
return 0;
}