zoukankan      html  css  js  c++  java
  • CF859D Third Month Insanity

    洛咕

    题意:有(2^n)个人要进行比赛,每次(2i)(2i+1)号人进行比赛.这一轮中赢的人进入下一轮.下一轮比赛的时候把进入这一轮的人按编号排好,仍然是像之前那样相邻的进行一次比赛.最后只剩下一个人.数据给出对于$ x,y(,)x(打赢)y(的概率.第)i$轮比赛会角逐出(2^{n-i})个赢家.我们要在比赛开始前,猜每轮的赢家(一轮的赢家一定要是上一轮的赢家).第$ i $轮每猜中一个赢家就会得到(2^{i-1})的得分.求最大的期望得分.(n<=6)

    分析:不难发现整个比赛其实是一棵完全二叉树,树的第i层代表第i轮比赛,树上的每个节点都代表一个区间(这一轮的参赛人的编号).

    所以我们考虑在树上dfs,设(w[i][j])表示在以i号节点为根的树中(即在第i轮比赛中)j获胜的概率.设(f[i][j])表示在以i号节点为根的树中(即在第i轮比赛中)j获胜的最大期望得分.

    对于w数组的转移,我们只要从左子树和右子树中分别选一个节点,然后结合概率来算就好了.对于f数组的转移,一定要在w数组转移之后,同样是从左子树和右子树中分别选一个节点,然后算期望就好了.具体的转移方程直接看代码吧,很好理解.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=105;
    double p[N][N],w[N*10][N],f[N*10][N];
    inline void dfs(int root,int l,int r,int val){
    	if(l==r){//叶子节点,即最后一轮比赛
    		w[root][l]=1;
    		f[root][l]=val;
    		return;
    	}
    	int mid=(l+r)>>1;
    	dfs(root<<1,l,mid,val/2);
    	dfs(root<<1|1,mid+1,r,val/2);
    	for(int i=l;i<=mid;++i)
    		for(int j=mid+1;j<=r;++j){
    			w[root][i]+=w[root<<1][i]*w[root<<1|1][j]*p[i][j];
    		}
    	for(int i=mid+1;i<=r;++i)
    		for(int j=l;j<=mid;++j){
    			w[root][i]+=w[root<<1][j]*w[root<<1|1][i]*p[i][j];
    		}
    	for(int i=l;i<=mid;++i)
    		for(int j=mid+1;j<=r;++j){
    			f[root][i]=max(f[root][i],w[root][i]*val+f[root<<1][i]+f[root<<1|1][j]);
    		}
    	for(int i=mid+1;i<=r;++i)
    		for(int j=l;j<=mid;++j){
    			f[root][i]=max(f[root][i],w[root][i]*val+f[root<<1][j]+f[root<<1|1][i]);
    		}
    }
    int main(){
    	int n=read();n=1<<n;
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=n;++j){
    			int x=read();
    			p[i][j]=0.01*x;//把整数变为概率
    		}
    	}
    	dfs(1,1,n,n/2);double ans=0.0;
    	for(int i=1;i<=n;++i)ans=max(ans,f[1][i]);
    	printf("%.10lf
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    String系列
    java初始化构造函数调用顺序
    转发和重定向的区别
    HttpServletResponse对象
    JSP九大隐式对象
    关于异常
    MySQL下载、安装及启动
    MySQL的启动
    MySQL下载及安装
    U盘安装Win7操作系统
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11534441.html
Copyright © 2011-2022 走看看