题目来源: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 }