cf#341-C. Wet Shark and Flowers-数学-概率计算

。。。。

求的是 期望嘛。。。

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;
} 

 


你可能感兴趣的:(cf#341-C. Wet Shark and Flowers-数学-概率计算)