1. 程式人生 > 其它 >codeforces F - Sports Betting (概率dp)

codeforces F - Sports Betting (概率dp)

題目連結:https://codeforces.com/contest/1556/problem/F

可以證明,一定存在勝利者,且勝利者們在同一個強連通分量中(反證法),所以考慮列舉勝利者

\(dp[winners]\) 表示勝利者為 \(winners\) 的概率,則期望為 \(\sum_{winners}dp[winners]\times|winners|\)

由勝利者都在同一個強連通分量中的性質可知,所有勝利者都可以擊敗每一個非勝利者,否則與強連通分量矛盾

那麼計算 \(dp[winners]\) 可以考慮容斥,即列舉的 \(winners\) 可以擊敗所有非勝利者的情況中,減去勝利者為 \(winners\)

子集 \(sub\),同時 \(winners\sub\) 中的參賽者要擊敗所有其它參賽者的情況

時間複雜度 \(O(n^23^n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 17;
const int M = 1000000007;

int n;
int a[maxn], inv[2000010];
int dp[1<<maxn], w[maxn][maxn], in[maxn];

int qsm(int i, int po){
	int res = 1;
	while(po){
		if(po&1) res = 1ll * res * i % M;
		i = 1ll * i * i % M;
		po >>= 1;
	}
	return res;
}

int count(int s){
	int tmp = s;
	int cnt = 0;
	while(tmp){
		if(tmp & 1) ++cnt;
		tmp >>= 1;
	}
	return cnt;
}

int calc(int s){
	memset(in, 0, sizeof(in));
	for(int i = 0 ; i < n ; ++i){ if((s>>i) & 1) in[i] = 1; }
	
	int G = 1;
	for(int i = 0 ; i < n ; ++i) {
		if(!in[i]) continue;
		for(int j = 0 ; j < n ; ++j){
			if(in[j]) continue;
			G = 1ll * G * w[i][j] % M;
		}
	} 
	
	for(int s0 = s ; s0 ; s0 = (s0-1)&s){
		if(s == s0) continue;
		int g = 1;
		int r = (s^s0); 
		for(int i = 0 ; i < n ; ++i){
			if(!((r>>i)&1)) continue;
			for(int j = 0 ; j < n ; ++j){
				if(in[j]) continue;
				g = 1ll * g * w[i][j] % M;
			}
		}
		
		G = ((G - 1ll * dp[s0] * g % M) % M + M) % M;
	}
	dp[s] = G;
	
	return dp[s];
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 0 ; i < n ; ++i) a[i] = read();
	
	for(int i = 0 ; i < n ; ++i){
		for(int j = 0 ; j < n ; ++j){
			w[i][j] = 1ll * a[i] * qsm(a[i]+a[j], M-2) % M;
		}
	}
	
	int ans = 0;
	for(int i = 1 ; i < (1<<n) ; ++i){
		ans = (ans + 1ll * calc(i) * count(i) % M) % M;
	} 
	
	printf("%d\n", ans);
	
	return 0;
}