题解 Hunter

传送门

一看这题subtasks就觉得最后能直接推个柿子出来……然而没推出来

首先状压的部分分:发现只需要统计猎人1还没死的状态的贡献,其它情况可以continue掉,有45pts
至于正解……发现我们要求的实际上就是期望有多少个猎人死在猎人1之前
发现每个猎人的死活之间相互独立,所以可以拆成每个猎人死在猎人1之前都能造成1贡献
考虑对于一对猎人 \(i,j\)\(i\) 死在 \(j\) 前面的概率是多少
分情况讨论:

  1. 两人都活着:是 \(\frac{w[i]}{w[i]+w[j]}\)
  2. 有一人活着:发现是情况1的附属状态,不贡献概率
  3. 都死了:同上不贡献概率

所以…… \(i\) 死在 \(j\) 前面的概率就是一个 \(\frac{w[i]}{w[i]+w[j]}\) ,没了
至于贡献……把所有概率加和就行了

神仙题……

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define reg register int
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
const ll mod=998244353;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
ll w[N];

ll qpow(ll a, ll b) {
	ll ans=1;
	while (b) {
		if (b&1) ans=ans*a%mod;
		a=a*a%mod; b>>=1;
	}
	return ans;
}

namespace force{
	ll ans, p[1<<21];
	void solve() {
		int lim=1<<n;
		ll sum, p2, tem;
		p[0]=1;
		for (reg s=0,cnt; s<lim; ++s) {
			if (s&1) continue;
			sum=0; cnt=1;
			for (reg i=0; i<n; ++i) 
				if (!(s&(1<<i))) md(sum, w[i+1]);
				else ++cnt;
			p2=qpow(sum, mod-2);
			//cout<<"s: "<<bitset<5>(s)<<endl;
			//cout<<p[s]<<' '<<w[1]<<' '<<p2<<endl;
			tem=p[s]*p2%mod;
			if (!(s&1)) md(ans, tem*cnt*w[1]%mod); //, cout<<"ans: "<<ans<<endl;
			for (reg i=0; i<n; ++i) if (!(s&(1<<i))) {
				md(p[s|(1<<i)], tem*w[i+1]%mod);
				//cout<<p[s]*w[i+1]%mod*p2%mod<<endl;
			}
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task{
	void solve() {
		ll ans=0;
		for (int i=2; i<=n; ++i) ans=(ans+w[i]*qpow((w[1]+w[i])%mod, mod-2)%mod)%mod;
		printf("%lld\n", ans+1);
		exit(0);
	}
}

signed main()
{
	n=read();
	for (int i=1; i<=n; ++i) w[i]=read();
	task::solve();
	
	return 0;
}
posted @ 2021-08-08 16:10  Administrator-09  阅读(12)  评论(0编辑  收藏  举报