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不能解决,那就三个……

  • 相关阅读:
    盒子垂直水平居中
    Sahi (2) —— https/SSL配置(102 Tutorial)
    Sahi (1) —— 快速入门(101 Tutorial)
    组织分析(1)——介绍
    Java Servlet (1) —— Filter过滤请求与响应
    CAS (8) —— Mac下配置CAS到JBoss EAP 6.4(6.x)的Standalone模式(服务端)
    JBoss Wildfly (1) —— 7.2.0.Final编译
    CAS (7) —— Mac下配置CAS 4.x的JPATicketRegistry(服务端)
    CAS (6) —— Nginx代理模式下浏览器访问CAS服务器网络顺序图详解
    CAS (5) —— Nginx代理模式下浏览器访问CAS服务器配置详解
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145217.html
Copyright © 2011-2022 走看看