济南学习 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 */
思路:看的别人的代码,没怎么看懂~~-_-