NOIP模拟测试15 T3 石头剪刀布
DP神题啊!刚考完试时波波说:“T3改不出来明天就别改了。”
似乎波波已经预料到这题很难改了?
首先设f[i][j][k][o]代表前i+j+k轮选了i个石头,j个布,k个剪刀并且下一个要选o的概率,
然后便可以枚举r(敌人),i,j,k,于是:
可以理解为把这n个人拍在一起
这里o的范围是[0,3],o==0代表的其实是g数组(取i,j,k的概率)
注意要从o转移到o,因为这样可以压行顺便g数组搞出来
有了f数组,接下来考虑如何统计答案:
其实就是把整个过程走一遍,三种情况取max,
最后乘上概率也就是那个组合数。(期望题也是硬伤啊~)
最后注意一下组合数要开long long
1 #include<bits/stdc++.h> 2 #define int long long 3 #define AA cout<<"Alita"<<endl 4 #define DD cout<<"Dybala"<<endl 5 #define m(a) memset(a,0,sizeof(a)) 6 using namespace std; 7 const int N=55; 8 int n,C[N][N]; 9 long double tot,p[N][4],f[N][N][N][4],ans; 10 signed main() 11 { 12 //freopen("1.in","r",stdin); 13 scanf("%lld",&n); 14 for(int i=1;i<=n;i++) 15 { 16 long double x,y,z; 17 scanf("%Lf%Lf%Lf",&x,&y,&z); 18 p[i][1]=x/300.0; //石头 19 p[i][2]=y/300.0; //布 20 p[i][3]=z/300.0; //剪刀 21 } 22 C[0][0]=1; 23 for(int i=1;i<=n;i++) 24 { 25 C[i][0]=1; 26 for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j]; 27 } 28 f[0][0][0][0]=1; 29 for(int r=1;r<=n;r++) 30 { 31 for(int i=r;i>=0;i--) 32 { 33 for(int j=r-i;j>=0;j--) 34 { 35 for(int k=r-i-j;k>=0;k--) 36 { 37 for(int o=3;o>=0;o--) 38 { 39 if(r==i+j+k) o=0; 40 if(i) f[i][j][k][o]+=f[i-1][j][k][o]*p[r][1]; 41 if(j) f[i][j][k][o]+=f[i][j-1][k][o]*p[r][2]; 42 if(k) f[i][j][k][o]+=f[i][j][k-1][o]*p[r][3]; 43 if(o) f[i][j][k][o]+=f[i][j][k][0]*p[r][o]; 44 } 45 } 46 } 47 } 48 } 49 for(int i=0;i<n;i++) 50 { 51 for(int j=0;j<n-i;j++) 52 { 53 for(int k=0;k<n-i-j;k++) 54 { 55 long double sum=0; 56 for(int l=1,p;l<=3;l++) 57 { 58 if(l==1) p=3; 59 else p=l-1; 60 sum=max(sum,f[i][j][k][l]+f[i][j][k][p]*3); 61 } 62 ans+=sum/(double)(C[n][i+j+k]*C[n-i-j-k][1]); 63 } 64 } 65 } 66 printf("%0.10Lf",ans); 67 return 0; 68 }