Problem

loj2541

题意概要:给定 \(n\) 个人的倒霉度 \(\{w_i\}\),每回合会有一个人死亡,每个人这回合死亡的概率为 自己的倒霉度/目前所有存活玩家的倒霉度之和,求第 \(1\) 个人最后一个死亡的概率

Solution

设 \(B = \sum_{i=2}^nw_i\)

要求 \(1\) 号最后一个被选中有点不好做,但是求 \(1\) 号第一个被选中还是比较好做的(\(\frac {w_1}{\sum_{i=1}^nw_i}\))

至于这两者怎么联系起来,使用 \(\mathrm {min-max}\) 容斥(和 HAOI2015按位或 有点像:前者是求 \(1\) 号最后一个被选中的概率;后者是求集合内最后一个被选中的期望次数)

\(\mathrm{min-max}\) 容斥的式子为:

\[\max\{S\}=\sum_{T\subseteq S}(-1)^{|T|-1}\min\{T\}
\]

由于 \(1\) 为需要求的点,将其从 \(S,T\) 的定义中刨除,即

\[\max\{S\}=\sum_{T\subseteq S}(-1)^{|T|}\min\{T\}
\]

而同时

\[\min\{T\}=\frac {w_1}{w_1+\sum_{x\in T}w_i}
\]

发现 \(\min\{T\}\) 最多有 \(B\) 种,可以考虑计算出每一项的容斥系数再 \(O(B)\) 计算

至于计算容斥系数,可使用母函数求得,即求出下面式子的每一项系数:

\[\prod_{i=2}^n(1-x^{w_i})
\]

分治 ntt 求解,每一层母函数度数和为 \(B\),复杂度 \(O(B\log B)\),总复杂度 \(O(B\log^2B)\)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline void read(int&x){
char ch=getchar();x=0;while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
} const int N = 200200, T = 37, p = 998244353;
int stk[T], tp;
int brr[T][N], L[T];
int w[N], rev[N]; inline int qm(const int&x) {return x < p ? x : x - p;}
inline int qpow(int A, int B) {
int res = 1; while(B) {
if(B&1) res = (ll)res * A%p;
A = (ll)A * A%p, B >>= 1;
} return res;
} void dft(int*a,int n,int sgn) {
for(int i=1;i<n;++i) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i=1;i<n;i<<=1) {
int gn = qpow(3, (p-1)/(i<<1));
for(int j=0;j<n;j+=(i<<1)) {
int g = 1;
for(int k=0;k<i;++k,g=(ll)g*gn%p) {
int x = a[j+k], y = (ll)g * a[j+k+i]%p;
a[j+k] = qm(x + y), a[j+k+i] = qm(x - y+p);
}
}
}
if(!sgn) {
int iv = qpow(n, p-2); reverse(a+1,a+n);
for(int i=0;i<n;++i) a[i] = (ll)a[i] * iv%p;
}
} void mul(int ai, int bi, int ci) {
int*ar = brr[ai], *br = brr[bi], *cr = brr[ci];
int n = L[ai], m = L[bi], &t = L[ci];
t = n + m; int nn = 1, l = 0;
while(nn < t) nn <<= 1, ++ l;
for(int i=n;i<nn;++i) ar[i] = 0;
for(int i=m;i<nn;++i) br[i] = 0;
for(int i=1;i<nn;++i) rev[i] = (rev[i>>1]>>1) | ((i&1) << l-1);
dft(ar, nn, 1), dft(br, nn, 1);
for(int i=0;i<nn;++i) cr[i] = (ll)ar[i] * br[i]%p;
dft(cr, nn, 0);
} int binary(int l, int r) {
if(l == r) {
int id = stk[--tp], *arr = brr[id];
for(int i=w[l]<<1;i;--i) arr[i] = 0;
arr[0] = 1, arr[w[l]] = p-1, L[id] = w[l]+1;
return id;
}
int mid = l + r >> 1;
int ls = binary(l, mid), rs = binary(mid+1, r);
int id = stk[--tp]; mul(ls, rs, id);
stk[tp++] = ls, stk[tp++] = rs;
return id;
} int main() {
for(int i=0;i<T;++i) stk[tp++] = T-i-1;
int n; read(n);
for(int i=1;i<=n;++i) read(w[i]);
int id = binary(2, n); int ans = 0, *arr = brr[id];
for(int i=0;i<L[id];++i)
ans = (ans + (ll)arr[i] * qpow(w[1] + i, p-2))%p;
ans = (ll)ans * w[1]%p;
printf("%d\n",ans);
return 0;
}

题解-PKUWC2018 猎人杀的更多相关文章

  1. [PKUWC2018]猎人杀

    题解 感觉是一道神题,想不出来 问最后\(1\)号猎人存活的概率 发现根本没法记录状态 每次转移的分母也都不一样 可以考虑这样一件事情: 如果一个人被打中了 那么不急于从所有人中将ta删除,而是给ta ...

  2. LOJ2541 PKUWC2018 猎人杀 期望、容斥、生成函数、分治

    传送门 首先,每一次有一个猎人死亡之后\(\sum w\)会变化,计算起来很麻烦,所以考虑在某一个猎人死亡之后给其打上标记,仍然计算他的\(w\),只是如果打中了一个打上了标记的人就重新选择.这样对应 ...

  3. LOJ2541 PKUWC2018猎人杀(概率期望+容斥原理+生成函数+分治NTT)

    考虑容斥,枚举一个子集S在1号猎人之后死.显然这个概率是w1/(Σwi+w1) (i∈S).于是我们统计出各种子集和的系数即可,造出一堆形如(-xwi+1)的生成函数,分治NTT卷起来就可以了. #i ...

  4. 洛谷 P5644 - [PKUWC2018]猎人杀(分治+NTT)

    题面传送门 很久之前(2020 年)就听说过这题了,这么经典的题怎么能只听说而亲自做一遍呢 首先注意到每次开枪打死一个猎人之后,打死其他猎人概率的分母就会发生变化,这将使我们维护起来非常棘手,因此我们 ...

  5. [LOJ2541][PKUWC2018]猎人杀(容斥+分治+FFT)

    https://blog.csdn.net/Maxwei_wzj/article/details/80714129 n个二项式相乘可以用分治+FFT的方法,使用空间回收可以只开log个数组. #inc ...

  6. 【洛谷5644】[PKUWC2018] 猎人杀(容斥+生成函数+分治NTT)

    点此看题面 大致题意: 有\(n\)个人相互开枪,每个人有一个仇恨度\(a_i\),每个人死后会开枪再打死另一个还活着的人,且第一枪由你打响.设当前剩余人仇恨度总和为\(k\),则每个人被打中的概率为 ...

  7. [LOJ2541] [PKUWC2018] 猎人杀

    题目链接 LOJ:https://loj.ac/problem/2541 Solution 很巧妙的思路. 注意到运行的过程中概率的分母在不停的变化,这样会让我们很不好算,我们考虑这样转化:假设所有人 ...

  8. 【LOJ2541】【PKUWC2018】猎人杀(容斥,FFT)

    [LOJ2541][PKUWC2018]猎人杀(容斥,FFT) 题面 LOJ 题解 这题好神仙啊. 直接考虑概率很麻烦,因为分母总是在变化. 但是,如果一个人死亡之后,我们不让他离场,假装给他打一个标 ...

  9. 「PKUWC2018」猎人杀

    「PKUWC2018」猎人杀 解题思路 首先有一个很妙的结论是问题可以转化为已经死掉的猎人继续算在概率里面,每一轮一直开枪直到射死一个之前没死的猎人为止. 证明,设所有猎人的概率之和为 \(W\) , ...

随机推荐

  1. php手记之01-tp5框架安装

    1.1.介绍 在web领域,PHP是所有编程语言中比较受欢迎的一门语言! PHP已经诞生出几十种编程框架!但国内最热门和使用率最好的框架有Thinkphp和Laravel这两款PHP框架! 1.2.为 ...

  2. sql 从服务器取消主从复制

    mysql>change master to master_host='' mysql>stop slave;reset slave;

  3. 你的Node应用,对接分布式链路跟踪系统了吗?(一) 原创: 金炳 Node全栈进阶 4天前 戳蓝字「Node全栈进阶」关注我们哦

    你的Node应用,对接分布式链路跟踪系统了吗?(一) 原创: 金炳 Node全栈进阶 4天前 戳蓝字「Node全栈进阶」关注我们哦

  4. protobuf protocol-buffers 序列化数据 gobs pickling string XML 用C实现的cPickle比pickle快1000倍 protobuf2 protobuf3 差异

    场景: 浏览器请求--->python数据生成--->python-生成excel--->浏览器下载excel 目标: 重构为 浏览器请求--->python数据生成---&g ...

  5. Docs-.NET-C#-指南-语言参考-预处理器指令:C# 预处理器指令

    ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:C# 预处理器指令 1.返回顶部 1. C# 预处理器指令 2015/07/20 本节介绍了以下 C# 预处理器指令: #if ...

  6. django模型多对多调用

    对于如下的模型: from django.db import models # Create your models here. class Student(models.Model): name = ...

  7. Spring走向注解驱动编程

    SpringFramework的两大核心,IOC(Inversion of control)控制反转和DI(Dependency Inject)依赖注入,其推崇的理念是应用系统不应以java代码的方式 ...

  8. Jmeter响应断言--正则表达式判断纯数字

    如图所示,这样是匹配14位数字,如果响应是纯数字可以直接用上

  9. 123456123456#0#-----com.threeapp.xiongMaoPaoPao01----熊猫跑酷01

    com.threeapp.xiongMaoPaoPao01----熊猫跑酷01

  10. mysql创建数据库、表、写数据

    mysql> create database ceshi; Query OK, 1 row affected (0.01 sec) 给数据库授权,否则程序时无法连接ceshi数据库的,每次创建一 ...