zoukankan      html  css  js  c++  java
  • [PKUWC2018]猎人杀

    sol

    一道容斥题,要结合生成函数。

    首先有个技巧:设猎人(i)还活着,他被开枪的概率为剩下猎人中按权值分配的概率,这样很麻烦,还需要知道剩余哪些人,其实等价于人都在,但被开枪到死人时要重新开枪的概率。因为对于活着的猎人,被开枪仍然概率不变。这点很重要,因为仍然可以用(p_i=dfrac{w_i}{tot})表示概率,其中(tot=sumlimits_j w_j)

    直接算出来(1)号猎人最后挂掉的概率很麻烦,考虑容斥。设集合(Ssubset{2,3,dots,n})表示猎人编号的集合,则可以容斥得到

    [ans=1+sum_{S}(-1)^{mid Smid}Pr(S) ]

    (Pr(S))表示挂在(1)号猎人后面至少为(S)中的猎人的概率。现在来分析这个东西,那么显然前面若干次一定是(overline S)中的人,除了(1)号被淘汰时立刻停止,否则继续。显然是一个无穷级数的求和。记(tot=sum w_i)(sum=sum_{iin S}w_i),那么有

    [egin{aligned} Pr(S)&=sum_{i=0}^inftyleft(dfrac{tot-sum-w_1}{tot} ight)^i imes dfrac{w_1}{tot}\ &=dfrac{1}{1-dfrac{tot-sum-w_i}{tot}} imesdfrac{w_1}{tot}\ &=dfrac{w_1}{sum+w_1} end{aligned} ]

    那么上面的式子就变成

    [ans=1+sum_S(-1)^{mid Smid}dfrac{w_1}{tot+w_1} ]

    根据数据范围提示,转变枚举方式,考虑枚举(tot),这个与(S)有关,记(f(i)=sum_{tot=i}(-1)^{mid Smid}),那么式子就变成了

    [ans=1+sum_{i}f(i)dfrac{w_1}{i+w_1} ]

    问题就变成了求解(f)。使用生成函数构造出(f),令(F=prod(1-x^{w_i})),则(f(i)=[x^i]F(x))。至此问题得解。

    #include <bits/stdc++.h>
    using std::swap; using std::reverse;
    typedef std::vector<int> Poly;
    const int N = 100005, P = 998244353;
    int n, w[N], L = 0;
    int inc(int a, int b) { return (a += b) >= P ? a-P : a; }
    int qpow(int a, int b) {
    	int t = 1;
    	for (; b; b >>= 1, a = 1LL*a*a%P)
    		if (b & 1) t = 1LL*t*a%P;
    	return t;
    }
    int W[N*2];
    void prework(int n) {
    	for (int i = 1; i < n; i <<= 1)
    		for (int j = W[i] = 1, Wn = qpow(3, (P-1)/i>>1); j < i; j++)
    			W[i+j] = 1LL*W[i+j-1]*Wn%P;
    }
    void fft(Poly &a, int n, int op) {
    	a.resize(n);
    	static int rev[N*2];
    	for (int i = 1; i < n; i++)
    		if ((rev[i] = rev[i>>1]>>1|(i&1?n>>1:0)) > i) swap(a[i], a[rev[i]]);
    	for (int q = 1; q < n; q <<= 1)
    		for (int p = 0; p < n; p += q<<1)
    			for (int i = 0, t; i < q; i++)
    				t = 1LL*W[q+i]*a[p+q+i]%P, a[p+q+i] = inc(a[p+i], P-t), a[p+i] = inc(a[p+i], t);
    	if (op) return;
    	for (int i = 0, inv = qpow(n, P-2); i < n; i++) a[i] = 1LL*a[i]*inv%P;
    	reverse(a.begin()+1, a.end());
    }
    void fix(Poly &A) { int x = A.size(); while (x > 1 && !A[x-1]) x--; A.resize(x); }
    int getsz(int n) { int x = 1; while (x < n) x <<= 1; return x; }
    Poly operator * (Poly A, Poly B) {
    	int L = getsz(A.size() + B.size() - 1);
    	fft(A, L, 1), fft(B, L, 1);
    	for (int i = 0; i < L; i++) A[i] = 1LL*A[i]*B[i]%P;
    	return fft(A, L, 0), fix(A), A;
    }
    Poly A[N*4]; int ans = 0;
    void build(int o, int l, int r) {
    	if (l == r) {
    		A[o] = Poly(w[l]+1); A[o][0] = P-1; A[o][w[l]] = 1;
    		return;
    	}
    	int mid = l+r>>1;
    	build(o<<1, l, mid), build(o<<1|1, mid+1, r);
    	A[o] = A[o<<1] * A[o<<1|1];
    }
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) scanf("%d", &w[i]), L += w[i];
    	prework(L);
    	build(1, 2, n);
    	for (int i = 0; i < A[1].size(); i++)
    		ans = (ans + 1LL*A[1][i]*L%P*qpow(L-i, P-2)) % P;
    	ans = 1LL*ans*w[1]%P*qpow(L, P-2)%P;
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    C# 操作Orcle数据库
    WinDbg排查CPU高的问题
    NetCore微服务实战体系:日志管理
    NetCore微服务实战体系:Grpc+Consul 服务发现
    解惑求助-关于NetCore2.2中间件响应的问题
    EF Join连接查询的坑
    给DataTable添加行的几种方式
    [C#] 折腾海康威视的人体测温 模组
    [WPF 学习] 15.播放百度合成的语音
    [WPF 学习] 14.PlaceHolder的简单实现
  • 原文地址:https://www.cnblogs.com/ac-evil/p/12838929.html
Copyright © 2011-2022 走看看