题意:给你n组范围,然后在每组范围里面随机选出一个值,为si,然后再给出一个素数P,si和sj是相邻的两个数字(s0和sn-1是相邻的),如果si*sj是P的倍数,那么si和sj就可以得到1000元,在n个范围中,每个范围都随机选出一个数字之后,就进行总结,然后得到总的钱,问这个钱的期望值。
思路:求期望值,也就是算每个范围选出的那个数字的贡献值,那么这个贡献值怎么算呢,如果si*sj是P的倍数,那么si和sj中至少有一个是P的倍数,假设我们现在要求的是si的贡献值,那么就有三种可能,si是P的倍数,si-1是P的倍数,si+1是P的倍数,那么当si是P的倍数的时候,无论si-1和si+1是不是P的倍数,si都能得到2000,因为si*si-1是P的倍数,si*si+1是P的倍数,叠加起来就是2000,如果si不是P的倍数,那么如果si-1或者si+1是P的倍数,si都能获得1000,那么假设si是P的倍数的概率是ai,那么si-1是P的倍数的概率是ai-1,si+1是P的倍数的概率是ai+1,那么公式就是ai*2000+(1-ai)*(ai-1)*1000+(1-ai)*(ai+1)*1000
P.S. 一开始我是依照样例来推导,然后也得到了一个公式,但是那个公式到处都是阶乘,用代码实现起来简直就是不现实的,然后问了同学,才把这个公式推导出来
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<math.h> 5 #include<algorithm> 6 #include<vector> 7 #include<string> 8 #include<queue> 9 #include<map> 10 #include<stack> 11 #include<set> 12 #define ll long long 13 #define maxn 100010 14 #define PI acos(-1.0) //圆周率 15 const ll INF = 1e18; 16 using namespace std; 17 struct node{ 18 ll l; 19 ll r; 20 ll fm; 21 ll fz; 22 double pro; 23 }num[maxn]; 24 ll n,p; 25 int main() 26 { 27 scanf("%I64d %I64d",&n,&p); 28 for(int i=0;i<n;i++){ 29 scanf("%I64d %I64d",&num[i].l,&num[i].r); 30 num[i].fz=num[i].r/p-num[i].l/p; 31 if(num[i].l%p==0) num[i].fz++; 32 num[i].fm=num[i].r-num[i].l+1; 33 num[i].pro=num[i].fz*1.0/num[i].fm*1.0; 34 } 35 36 double ans=0; 37 for(int i=0;i<n;i++){ 38 if(i==0){ 39 ans+=num[i].pro*2000+(1-num[i].pro)*1000*(num[n-1].pro+num[i+1].pro); 40 } 41 else if(i==n-1){ 42 ans+=num[i].pro*2000+(1-num[i].pro)*1000*(num[i-1].pro+num[0].pro); 43 } 44 else{ 45 ans+=num[i].pro*2000+(1-num[i].pro)*1000*(num[i-1].pro+num[i+1].pro); 46 } 47 } 48 49 printf("%.6lf\n",ans); 50 51 return 0; 52 }