。。。。
求的是 期望嘛。。。
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; }