首页 > 其他分享 >[PKUWC2018]猎人杀

[PKUWC2018]猎人杀

时间:2023-05-02 19:34:17浏览次数:57  
标签:return int poly 猎人 mul inline PKUWC2018 size

概率的分母在不断变化很麻烦,我们不妨令它可以打到已死的人。由于还活着的人概率之比没有变,显然是不会影响答案的。

考虑容斥,设 \(p(S)\) 表示集合 \(S\) 中的人在 \(1\) 后被打的方案数,那么答案就是 \(\sum_{S}(-1)^{|S|}p(S)\)。\(p(S)\) 实际上就是无限开枪,每次不打 \(S\cup \{1\}\) 的概率,枚举打到 \(1\) 之前打了多少次,令 \(sum=\sum w_i\),则容易得到 \(p(S)=\sum \left({sum-w_1-\operatorname{sum}(S)\over sum}\right)^i\cdot {w_1\over sum}\)。这是个等比数列,容易得到 \({a_1\over a_1+\operatorname{sum}(S)}\)

再看答案的式子,枚举 \(S\) 是指数级的,不好算。观察数据范围我们发现 \(sum\) 只有 \(10^5\) 的级别,不妨直接枚举 \(sum\)。令 \(f(i)=\sum\limits_{\operatorname{sum}(S)=i}(-1)^{|S|}\),答案容易算出。关键在求 \(f(i)\),考虑生成函数。显然 \(f(i)=[x^i] \prod\limits_{i=2}^{n} 1-x^{w_i}\)。取 \(\ln\) 之后 \(\exp\) 即可。

#include <bits/stdc++.h>

using namespace std;

#define pi pair<int,int>
#define mp make_pair
#define poly vector<int>

const int N = 4e5 + 5, mod = 998244353, G = 3, I = 86583718, Gi = 332748118;

const int add(int a, int b) { return (a + b) >= mod ? a + b - mod : a + b; }
const int sub(int a, int b) { return a < b ? a - b + mod : a - b; }
const int mul(int a, int b) { return (1ll * a * b) % mod; }

const int power(int a, int b) {
	int t = 1, y = a, k = b;
	while (k) {
		if (k & 1) t = mul(t, y);
		y = mul(y, y); k >>= 1;
	} return t;
}

const int inv2 = power(2, mod - 2), inv2I = power(mul(2, I), mod - 2);

inline int read() {
	register int s = 0, f = 1; register char ch = getchar();
	while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
	while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
	return s * f;
}

inline void FFT(int *a, int len, int typ) {
	for (int i = 0, j = 0, k; i < len; ++i) {
		if (i < j) swap(a[i], a[j]);
		for (k = len >> 1; k & j; k >>= 1) j ^= k;
		j ^= k;
	}
	for (int mid = 1; mid < len; mid <<= 1) {
		int wn = power(typ == 1 ? G : Gi, (mod - 1) / (mid << 1));
		for (int j = 0; j < len; j += mid << 1) {
			int bas = 1;
			for (int k = 0; k < mid; ++k, bas = mul(bas, wn)) {
				int x = a[j + k], y = ::mul(bas, a[j + mid + k]);
				a[j + k] = ::add(x, y);
				a[j + mid + k] = ::sub(x, y);
			}
		}
	}
	if (!typ) {
		const int iv = power(len, mod - 2);
		for (int i = 0; i < len; ++i)
			a[i] = ::mul(a[i], iv);
	}
}

inline int max_(int a, int b) {
	return a > b ? a : b;
}

inline int min_(int a, int b) {
	return a < b ? a : b;
}

inline poly add(poly a, int b) {
	for (int i = 0; i < a.size(); ++i) a[i] = ::add(a[i], b);
	return a;
}

inline poly sub(poly a, int b) {
	for (int i = 0; i < a.size(); ++i) a[i] = ::sub(a[i], b);
	return a;
}

inline poly mul(poly a, int b) {
	for (int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
	return a;
}

inline poly div(poly a, int b) {
	b = ::power(b, mod - 2);
	for (int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
	return a;
}

inline poly add(poly a, poly b) {
	a.resize(max_(a.size(), b.size()));
	for (int i = 0; i < b.size(); ++i) a[i] = ::add(a[i], b[i]);
	return a;
}

inline poly sub(poly a, poly b) {
	a.resize(max_(a.size(), b.size()));
	for (int i = 0; i < b.size(); ++i) a[i] = ::sub(a[i], b[i]);
	return a;
}

inline poly mul(poly a, poly b) {
	int p = a.size() + b.size() - 1; int len = 1 << (int)ceil(log2(p));
	a.resize(len); b.resize(len);
	FFT(&a[0], len, 1); FFT(&b[0], len, 1);
	for (int i = 0; i < len; ++i)
		a[i] = ::mul(a[i], b[i]);
	FFT(&a[0], len, 0); a.resize(p);
	return a;
}

inline poly inv(poly a, int len) {
	if (len == 1) return poly(1, power(a[0], mod - 2));
	int n = 1 << ((int)ceil(log2(len)) + 1);
	poly x = inv(a, len + 1 >> 1), y;
	x.resize(n); y.resize(n);
	for (int i = 0; i < len; ++i) y[i] = a[i];
	FFT(&x[0], n, 1); FFT(&y[0], n, 1);
	for (int i = 0; i < n; ++i) x[i] = ::mul(x[i], ::sub(2, ::mul(x[i], y[i])));
	FFT(&x[0], n, 0);
	x.resize(len);
	return x;
}

inline poly inv(poly a) {
	return inv(a, a.size());
}

inline poly rev(poly a) {
	reverse(a.begin(), a.end());
	return a;
}

inline poly div(poly a, poly b) {
	if (a.size() < b.size()) return poly(1, 0);
	int p = a.size() - b.size() + 1;
	poly ra = rev(a), rb = rev(b);
	ra.resize(p), rb.resize(p);
	ra = mul(ra, inv(rb));
	ra.resize(p);
	return rev(ra);
}

inline poly remainder(poly a, poly b) {
	if (a.size() < b.size()) return a;
	poly c = div(a, b), d = sub(a, mul(b, c));
	while (d.size() && !d.back()) d.pop_back();
	if (!d.size()) d = poly(1, 0);
	return d;
}

inline poly det(poly a) {
	int n = a.size();
	for (int i = 1; i < n; ++i) a[i - 1] = ::mul(a[i], i);
	a.resize(n - 1);
	return a;
}

inline poly inter(poly a) {
	int n = a.size(); a.resize(n + 1);
	for (int i = n; i >= 1; --i)
		a[i] = ::mul(a[i - 1], power(i, mod - 2));
	a[0] = 0; return a;
}

inline poly ln(poly a) {
	int n = a.size();
	a = inter(mul(det(a), inv(a)));
	a.resize(n); return a;
}

inline poly exp(poly a, int len) {
	if (len == 1) return poly(1, 1);
	poly x = exp(a, len + 1 >> 1); x.resize(len);
	poly y = ln(x);
	for (int i = 0; i < len; ++i) y[i] = ::sub(a[i], y[i]);
	++y[0]; x = mul(x, y); x.resize(len);
	return x;
}

inline poly exp(poly a) {
	return exp(a, a.size());
}

int n, inver[N], tim[N], sum = 0, w[N];
poly a;

int main() {
	n = read();
	for (int i = 1; i <= n; ++i)
		sum += w[i] = read();
	a.resize(sum + 1);
	for (int i = 2; i <= n; ++i) ++tim[w[i]];
	for (int i = 1; i <= sum; ++i) inver[i] = power(i, mod - 2);
	for (int i = 1; i <= sum; ++i)
		if (tim[i])
			for (int j = 1; j <= sum / i; ++j)
				a[j * i] = sub(a[j * i], ::mul(inver[j], tim[i]));
	a = exp(a); int res = 0;
	for (int i = 0; i <= sum; ++i) {
		res += 1ll * a[i] * (1ll * w[1] * power(w[1] + i, mod - 2) % mod) % mod;
		if (res >= mod) res -= mod;
	} printf("%d\n", res);
	return 0;
}

标签:return,int,poly,猎人,mul,inline,PKUWC2018,size
From: https://www.cnblogs.com/wwlwakioi/p/17368088.html

相关文章

  • 【心得】Man at Work3--猎人的青春!
    【心得】ManatWork3--猎人的青春! 这是我接触到的第1款3DGAL游戏。里面的5个女孩子:“贾斯丁”,“菲利丝”,“凌小路瑞惠”,“莫妮卡”以及“莉莎”在我没怎么看攻略的情况下,就凭借着一腔热血以及永不消逝的耐心,终于一一攻破了...值得我骄傲的是,我并没有在离“热恋”差1的情况下,存......
  • 「题解」洛谷 P5644 [PKUWC2018]猎人杀
    题意:初始有\(n\)个人,每个人的权值是\(w_i\),假设这一轮剩余还没嘎掉的人总权值是\(s\),那么这一轮它有\(\frac{w_i}{s}\)的概率嘎掉。求\(1\)活到最后的概率是多少。......
  • 【题解】P5644 [PKUWC2018]猎人杀
    供题人是树剖姐姐喵/se思路生成函数+子集反演+分治NTT.首先发现当前打中的猎人倒下之后,后面的猎人被射中的概率会随之变化,也就是说操作是有后效性的,不好处理。有......
  • [PKUWC2018]随机游走
    第一次做用待定系数法解决树上期望dp的题。首先这道题很显然可以\(min-max\)容斥一下,转化成到达点集\(S\)一个点的期望步数。考虑这个怎么求。设\(f_u\)表示从\(u......
  • 【题解】洛谷-P5643 [PKUWC2018]随机游走
    用到了概率期望的很多技巧。首先要求的是走遍集合中所有节点步数的期望,也就是步数最大值的期望,根据\(\text{min-max}\)容斥,有:\[E\left(\max_{i\inS}x_i\right)=\sum_......
  • 【题解】P5298 [PKUWC2018]Minimax
    P5298[PKUWC2018]Minimax思路线段树合并优化树形dp.值域1e9首先考虑离散化。然后发现需要维护每种权值的出现概率,于是可以考虑到一个简单的树形dp:设\(f[i][j]\)......
  • P5298 [PKUWC2018]Minimax
    题解\(f_{u,k}\)节点\(u\)是第\(k\)小的点的概率。\(deg=2\)的情况:\[f_{u,k}=(1-p_u)\left(f_{lc,k}\sum_{k'>k}f_{rc,k'}+f_{rc,k}\sum_{k'>k}f_{lc,k'}+f_{lc......
  • 赏金猎人笔记-手动sqli
      声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。本文选......
  • 赏金猎人笔记-sqli几个小技巧
      几个技巧小结1.查找后台登陆界面:google:“www.target.comlogin”有效率达到60%的一个sqli的payload:2.sqli一个有效载荷:admin'OR1=1--'3.对于类似这种:......
  • 赏金猎人系列-如何测试注册(Sign up)功能III以及相关Tips
      赏金猎人系列-如何测试注册(Signup)功能III以及相关Tips声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部......