Problem B. Black Peter Solution

题目来源:19youzu

f[0][n]表示特殊牌在自己,轮到自己(0),n个未配对牌时,自己赢的概率

g[0][n]表示特殊牌在对面,轮到自己(0),n个未配对牌时,自己赢的概率

关系:g[0][n]=1- f[1][n];f[0][n]=1- g[1][n]

因为特殊牌在自己且轮到自己时,自己赢的概率,等于特殊牌在对面且轮到对面时,自己输的概率,输赢概率和为1

第一维1表示轮到对面

我们需要第一维为0(因为题中一直是自己先手),所以消去g[1], f[1]

递推:

(1)g[0][n]=n/(n+1)*g[1][n-1]+1/(n+1)*f[1][n]

= n/(n+1)*g[1][n-1]+1/(n+1)*(1-g[0][n])

(2)f[0][n]= f[1][n-1]=1-g[0][n-1]

(注意f和g的递推式不一样,很容易误以为是对称的)

化简(1):

g[0][n]=1/(n+2)+n/(n+2)*g[1][n-1]

化简(2):

f[0][n]= 1-g[0][n-1]

我们要去掉第一维是1的

g[0][n]=1/(n+2)+n/(n+2)*(1-f[0][n-1])

f[0][n]= 1-g[0][n-1]

下面,就可以把g[0]写成g,f[0]写成f了

g[n]=1/(n+2)+n/(n+2)*(1-f[n-1])

f[n]= 1-g[n-1]

初始条件:g[0]=1, f[0]=0

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long LL;
 5 
 6 char a[1000500]={0};
 7 char b[1000500]={0};
 8 double f[1000000],g[1000000];
 9 int main(){
10     int r;
11     cin>>r;
12     for(int i=0;i<r;i++){
13         int n;
14         scanf("%d\n",&n);
15         int count=n,count1a=0,count1b=0;
16 //        memset(a,0,sizeof(a));
17 //        memset(a,0,sizeof(b));
18 //        cin.getline(a,n);
19 //        cin.getline(b,n);
20         scanf("%s",a);
21         scanf("%s",b);
22 //        getchar();
23         for(int k=0;k<n;k++){
24             if(a[k]=='1'){
25                 count1a++;
26             }
27         }
28         for(int k=0;k<n;k++){
29             if(b[k]=='1'){
30                 count1b++;
31             }
32         }
33         int count1=min(count1a,count1b);
34 
35 
36 //        memset(f,0,sizeof(f));
37 //        memset(g,0,sizeof(g));
38         g[0]=1, f[0]=0;
39         for(int j=1;j<=count1;j++){
40             g[j]=1.0/(double)(j+2)+(double)j/(double)(j+2)*(1-f[j-1]);
41 
42             f[j]=1-g[j-1];
43 
44         }
45         if(count1a>count1b){
46             cout<<setprecision(15)<<f[count1]<<endl;
47         }
48         if(count1a<count1b){
49             cout<<setprecision(15)<<g[count1]<<endl;
50 
51         }
52     }
53 }

猜你喜欢

转载自www.cnblogs.com/Kinghao0319/p/12917298.html