zoukankan      html  css  js  c++  java
  • [JZOJ3168] 【GDOI2013模拟3】踢足球

    题目

    描述

    在这里插入图片描述

    题目大意

    有两个队伍,每个队伍各nn人。
    接到球的某个人会再下一刻随机地传给自己人、敌人和射门,射门有概率会中。
    每次射门之后球权在对方11号选手。
    某个队伍到了RR分,或者总时间到达TT时,比赛结束。
    询问每种比分的概率。


    思考历程

    一看就觉得这是一道DP
    设一个五维的状态,其中两维表示比分,一维表示时间,一维表示分数,还有一维表示球权。
    不得不说这是最粗暴的方法。
    接着呢……想了很久就没有去想了,甚至连暴力也没有打。


    正解

    正解还是DP。
    我们试着给DP降维打击,机智的DYP大佬就想到了省去球权的这一维。
    因为题目有个重要的性质:当一个球队射门之后,球权必定在对方的11号选手。
    我们设fr1,r2,t,0/1f_{r1,r2,t,0/1}表示概率,r1r1r2r2表示比分,tt表示时间,后面的表示球权在哪个队(的11号选手)。
    让我们考虑一下从发球到其中一个队进球这个过程为单位的转移。
    我们再设g0/1,0/1,tg_{0/1,0/1,t}表示某个队发球,某个队进球,花了tt时间的概率。
    于是我们就可以通过gg来求出ff了。
    接着问题变成了如何求gg
    还是DP。
    h0/1,t,ih_{0/1,t,i}表示从某个队发球,花了tt时间,球权在ii的概率。
    在DP转移hh时,如果射门就会转移到gg,否则还是转移到hh
    这样题目就基本做完了。
    注意一点,在统计答案的时候,对于双方比分都没有到达RR的情况,我们需要枚举时间,用对应的ff值乘上在剩下时间中不进球的概率。
    显然,这个不进球的概率就是对应时间中hh值的和。


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 110
    #define maxR 11
    #define maxT 501
    int n,R,T;
    double score[N*2],p[N*2];
    int e[N*2][N*2];
    double h[2][maxT][N*2],g[2][2][maxT],f[maxR][maxR][maxT][2];
    double sumh[2][maxT];
    int main(){
    	scanf("%d%d%d",&n,&R,&T);
    	for (int i=1;i<=n;++i){
    		scanf("%lf",&score[i]);
    		int k1,k2;scanf("%d%d",&k1,&k2);
    		for (int j=1;j<=k1;++j){
    			int x;scanf("%d",&x);
    			e[i][x]=1;
    		}
    		for (int j=1;j<=k2;++j){
    			int x;scanf("%d",&x);
    			e[i][n+x]=1;
    		}
    		p[i]=1.0/(k1+k2+1);
    	}
    	for (int i=n+1;i<=2*n;++i){
    		scanf("%lf",&score[i]);
    		int k1,k2;scanf("%d%d",&k1,&k2);
    		for (int j=1;j<=k1;++j){
    			int x;scanf("%d",&x);
    			e[i][n+x]=1;
    		}
    		for (int j=1;j<=k2;++j){
    			int x;scanf("%d",&x);
    			e[i][x]=1;
    		}
    		p[i]=1.0/(k1+k2+1);
    	}
    	for (int st=0;st<=1;++st){
    		h[st][0][st*n+1]=1;
    		for (int j=0;j<T;++j)
    			for (int k=1;k<=2*n;++k){
    				if (k<=n){
    					g[st][0][j+1]+=h[st][j][k]*p[k]*score[k];
    					h[st][j+1][n+1]+=h[st][j][k]*p[k]*(1-score[k]);
    				}
    				else{
    					g[st][1][j+1]+=h[st][j][k]*p[k]*score[k];
    					h[st][j+1][1]+=h[st][j][k]*p[k]*(1-score[k]);
    				}
    				for (int l=1;l<=2*n;++l)
    					if (e[k][l])
    						h[st][j+1][l]+=h[st][j][k]*p[k];
    			}
    		for (int j=0;j<=T;++j)
    			for (int k=1;k<=2*n;++k)
    				sumh[st][j]+=h[st][j][k];
    	}
    	f[0][0][0][0]=1;
    	for (int i=0;i<R;++i)
    		for (int j=0;j<R;++j)
    			for (int k=0;k<T;++k)
    				for (int t=1;k+t<=T;++t){
    					f[i][j+1][k+t][0]+=f[i][j][k][0]*g[0][1][t]+f[i][j][k][1]*g[1][1][t];
    					f[i+1][j][k+t][1]+=f[i][j][k][0]*g[0][0][t]+f[i][j][k][1]*g[1][0][t];
    				}
    	for (int i=0;i<=R;++i)
    		for (int j=0;j<=R;++j){
    			double ans=0;
    			if (i<R && j<R){
    				for (int k=0;k<=T;++k)
    					ans+=f[i][j][k][0]*sumh[0][T-k]+f[i][j][k][1]*sumh[1][T-k];
    			}
    			else{
    				if (i==R && j==R)
    					break;
    				for (int k=0;k<=T;++k)
    					ans+=f[i][j][k][0]+f[i][j][k][1];
    			}	
    			printf("%.8lf
    ",ans);
    		}
    	return 0;
    }
    

    总结

    有时候一个DP不能解决,就用两个DP,如果两个DP不能解决,那就三个……

  • 相关阅读:
    【Android 系统开发】 Android 系统启动流程简介
    【Android 多媒体开发】 MediaPlayer 状态机 接口 方法 解析
    【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介
    Android 图表绘制 achartengine 示例解析
    【Android 应用开发】Activity 状态保存 OnSaveInstanceState参数解析
    【Android 应用开发】 Fragment 详解
    DevExpress GridView常用属性
    网页技术CSS元素的class与ID命名常用关键字(不断完善中,敬请关注) .
    bootstrap-wysiwyg 结合 base64 解码 .net bbs 图片操作类 (二) 图片裁剪
    bootstrap-wysiwyg 结合 base64 解码 .net bbs 图片操作类
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145217.html
Copyright © 2011-2022 走看看