济南学习 Day 2 T3 pm


【问题描述】
N个人坐成一圈,其中第K个人拿着一个球。每次每个人会以一定的概率向
左边的人和右边的人传球。当所有人都拿到过球之后,最后一个拿到球的人即为
胜者。求第N个人获胜的概率。 (所有人按照编号逆时针坐成一圈)
【输入格式】
第一行一个数T代表数据组数。
对于每组数据,第一行两个整数N,K如题意所述。
接下来每行一个实数p代表该人将球传给右边的人的概率。
【输出格式】
对于每组数据,一行一个实数代表答案,保留9位小数。
【样例输入】
1
5 1
0.10
0.20
0.30
0.40
0.50
【样例输出】
0.007692308
【样例解释】
然后鸟是我的。
【数据规模与约定】
对于20%的数据, N ≤ 3。
70%的数据,T,N ≤ 10。
对于100%的数据,T ≤ 10000,1≤ N ≤ 100。

 1 #include<cstdio>
 2 using namespace std;
 3 const int N=1000+10;
 4 int T,n,k,pre[N],next[N];
 5 long double p[N],q[N];
 6 void deal(int b){
 7     int a=pre[b],c=next[b];
 8     long double pa=p[a],pb=p[b],pc=p[c];
 9     p[a]=pa*pb/(1-pa*(1-pb));
10     q[a]=1-p[a];
11     q[c]=(1-pc)*(1-pb)/(1-pb*(1-pc));
12     p[c]=1-q[c];
13     next[a]=c;pre[c]=a;
14 }
15 long double solve(){
16     if(n<=2) return 1;
17     if(n<=3) return k==1?p[1]:q[2];
18     for(int i=1;i<=n;i++) pre[i]=i-1,next[i]=i+1;
19     pre[1]=n;next[n]=1;// 记录向左向右传递的概率 
20     if(k==1){
21         for(int i=2;i<n-1;i++) deal(i);
22         return p[1];
23     }
24     if(k==n-1){
25         for(int i=2;i<n-1;i++) deal(i);
26         return q[n-1];
27     }
28     for(int i=2;i<n-1;i++) if(i!=k) deal(i);
29     deal(k);
30     return q[k]*p[1]+p[k]*q[n-1];
31 }
32 double v;
33 #define name "it"
34 int main(){
35     scanf("%d",&T);
36     while(T--){
37         scanf("%d%d",&n,&k);
38         for(int i=1;i<=n;i++){
39             scanf("%lf",&v);
40             p[i]=v;
41             q[i]=1-v;
42         }
43         printf("%.9lf\n",(double)solve());
44     }
45     return 0;
46 }
47 /*
48 p 数组向左传的概率 
49 q 数组向右传的概率 
50 */

思路:看的别人的代码,没怎么看懂~~-_-

posted @ 2016-11-07 09:50  浮华的终成空  阅读(164)  评论(0编辑  收藏  举报

Contact with me