zoukankan      html  css  js  c++  java
  • CF1556F-Sports Betting【状压dp,数学期望】

    正题

    题目链接:https://www.luogu.com.cn/problem/CF1556F


    题目大意

    (n)个点的一张竞赛图,每个点有一个权值(a_i)((i,j))之间的边(i)(j)的概率是(frac{a_i}{a_i+a_j}),否则(j)(i)

    现在期望有多少个点能走到全图的任意一个点。

    (1leq nleq 14,1leq a_ileq 10^6)


    解题思路

    考虑状压(dp),首先枚举起点(p),设(f_{S})表示目前只考虑了点集(S)(p)都能到达。

    那么对于点集(S)是任意一张图的概率是(1),然后考虑枚举一个(p)能到达的集合(T)之后其他点(p)都不能到达,为了方便表示下面记(g_{S,T})表示点集(S)(T)之间的边都是(S)指向(T)的概率那么有

    [1=sum_{Tsubseteq S}f_T imes g_{S-T,T} ]

    [Rightarrow f_S=1-sum_{Tsubset S}f_T imes g_{S-T,T} ]

    考虑如何预处理(g_{S,T}),不难发现因为(Scap T=varnothing)所以这个状态数是(3^n)的我们可以用三进制状压,不过得先预处理(r_{p,S})表示(p)与集合(S)之间的边都是(p)连向(S)的概率。

    时间复杂度:(O(3^nn+2^nn^2))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=14,M=2e6+10,P=1e9+7;
    ll n,ans,inv[M],pw[N+1],a[N],r[N][1<<N],tr[1<<N],f[1<<N],g[4782969];
    signed main()
    {
    	inv[1]=1;
    	for(ll i=2;i<M;i++)inv[i]=P-(P/i)*inv[P%i]%P;
    	scanf("%lld",&n);
    	for(ll i=0;i<n;i++)
    		scanf("%lld",&a[i]);
    	ll MS=(1<<n);
    	for(ll p=0;p<n;p++){
    		r[p][0]=1;
    		for(ll s=0;s<MS;s++){
    			if((s>>p)&1)continue;
    			for(ll i=0;i<n;i++)
    				if((s>>i)&1){r[p][s]=r[p][s^(1<<i)]*a[p]%P*inv[a[p]+a[i]]%P;break;}
    		}
    	}
    	pw[0]=1;for(ll i=1;i<=n;i++)pw[i]=pw[i-1]*3;
    	for(ll s=1;s<MS;s++)
    		for(ll i=0;i<n;i++)
    			if((s>>i)&1)tr[s]=tr[s^(1<<i)]+pw[i];
    	for(ll s=0;s<pw[n];s++)g[s]=1;
    	for(ll s=0;s<MS;s++)
    		for(ll i=0;i<n;i++){
    			if(!((s>>i)&1))continue;
    			for(ll t=s;t;t=(t-1)&s){
    				if((t>>i)&1)continue;
    				(g[tr[s]+tr[t]]*=r[i][t])%=P;
    			}
    		}
    	for(ll p=0;p<n;p++){
    		memset(f,0,sizeof(f));
    		for(ll s=0;s<MS;s++){
    			if(!((s>>p)&1))continue;f[s]=1;
    			for(ll t=(s-1)&s;t;t=(t-1)&s){
    				if(!((t>>p)&1))continue;
    				(f[s]+=P-f[t]*g[tr[s]+tr[t]]%P)%=P;
    			}
    		}
    		(ans+=f[MS-1])%=P;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    二进制,八进制,十六进制,十进制之间的换算
    14简化路径(71)
    13字符串解码(394)
    12 反转每对括号间的子串(1190)
    11 使括号有效的最少添加(921)
    10 K 个一组翻转链表(25)
    9 从链表中删去总和值为零的连续节点(1171)
    8 链表中的下一个更大节点(1019)
    7两两交换链表中的节点(24)
    6 奇偶链表(
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15380613.html
Copyright © 2011-2022 走看看