Description

猎人杀是一款风靡一时的游戏“狼人杀”的民间版本,他的规则是这样的:

一开始有 n个猎人,第 i 个猎人有仇恨度 wi。每个猎人只有一个固定的技能:死亡后必须开一枪,且被射中的人也会死亡。

然而向谁开枪也是有讲究的,假设当前还活着的猎人有\([i_1...i_m]\),那么有\(w_{i_k}\over \sum\limits_{j=1}^{m} w_{i_j}\)的概率是向猎人\(i_k\) 开枪

一开始第一枪由你打响,目标的选择方法和猎人一样(即有\(w_{i}\over \sum\limits_{j=1}^{m} w_{j}\)的概率射中第i个猎人)。由于开枪导致的连锁反应,所有猎人最终都会死亡,现在1号猎人想知道它是最后一个死的的概率。

对998244353取模

\(w_i>0,\sum w_i\leq 100000\)

Solution

首先有结论,我们假设可以对已经死亡的猎人开枪,对已经死亡猎人开枪之后继续开枪,那么问题是等价的。

这样就好做不少,因为每个人中枪的概率就固定了。

根据这个结论,我们来推一波式子。

我们可以将整个开枪过程看做是一个序列,每个数可以出现多次,每个数出现有概率,题目问的是1出现时其他所有数都已经出现过的概率。

考虑指数型生成函数,设\(t=\sum w_k\),容易得出除1号外i号猎人的EGF是$$\sum\limits_{j>0}{w_ijxj\over tji!}=e{w_ix\over t}-1$$

那么将这些猎人拼接,总的式子就是$$\prod\limits_{k=2}{n}(e{w_kx\over t}-1)$$

假设有3个猎人,2,3号猎人拼在一起就是\(e^{(w_2+w_3)x\over t}-e^{w_2x\over t}-e^{w_3x\over t}+1\)

对于每个EGF,它对总概率的贡献就是其系数之和

对于\(e^{px}\),将其系数求和(不考虑阶乘),就是等比数列求和的形式,可以得出和就是\(1\over 1-p\)

那么对于上面的式子,一样计算和,然后加到一起,最后再乘上\(w_1/t\)(最后一次要选上1号)

现在问题的关键就是要算上面的乘积的每一项\(e^{px},p\in[0,t]\)的系数

我们可以把每个\(e^{px}\)也看做多项式的一项,因为同是指数相加,可以构造多项式\(x^{w_k\over t}-1\),那么$$\prod\limits_{k=2}{n}(x{w_k\over t}-1)$$

的每一项\(x^{p}\)前的系数就是原式中每一个\(e^{px}\)的系数

可以先不看t,用分治NTT做,最后再算上。

总复杂度\(O(n\log^2 n)\)

Code

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define M 262144
#define L 18
#define mo 998244353
#define LL long long
#define N 100005
using namespace std;
LL wi[M+1],wg[M+1],a[M+1],b[M+1],c[M+1],ny,w[N];
int a1[N],bit[M+1],sz[N],n1,n,sm[N],l2[M+1],cf[L+1],sum;
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
void prp(int num)
{
fo(i,0,num-1) bit[i]=(bit[i>>1]>>1)|((i&1)<<(l2[num]-1));
fo(i,0,num) wi[i]=wg[M/num*i];
ny=ksm(num,mo-2);
}
void NTT(LL *a,bool pd,int num)
{
LL v,w;
fo(i,0,num-1) if(i<bit[i]) swap(a[i],a[bit[i]]);
for(int m=2,lim=num>>1,half=1;m<=num;half=m,m<<=1,lim>>=1)
{
fo(i,0,half-1)
{
w=(!pd)?wi[i*lim]:wi[num-i*lim];
for(int j=i;j<num;j+=m)
{
v=a[j+half]*w%mo;
a[j+half]=(a[j]-v+mo)%mo;
a[j]=(a[j]+v)%mo;
}
}
}
if(pd) fo(i,0,num-1) a[i]=a[i]*ny%mo;
}
void doit(int l,int r)
{
if(l==r) return;
int mi=sm[n],mid=l;
fo(j,l,r-1) if(max(sm[j]-sm[l-1],sm[r]-sm[j])<mi) mi=max(sm[j]-sm[l-1],sm[r]-sm[j]),mid=j;
doit(l,mid),doit(mid+1,r);
int num=cf[l2[sz[mid+1]+sz[l]+1]];
prp(num);
fo(i,0,num-1) b[i]=c[i]=0;
fo(i,0,sz[l]) b[i]=a[a1[l]+i];
fo(i,0,sz[mid+1]) c[i]=a[a1[mid+1]+i];
NTT(b,0,num),NTT(c,0,num);
fo(i,0,num-1) b[i]=b[i]*c[i]%mo;
NTT(b,1,num);
sz[l]+=sz[mid+1];
fo(i,0,sz[l]) a[a1[l]+i]=b[i];
}
int main()
{
cin>>n;
int l=-1;
cf[0]=1;
fo(i,1,18) cf[i]=(cf[i-1]<<1),l2[cf[i]]=i;
fod(i,M-1,2) if(!l2[i]) l2[i]=l2[i+1];
fo(i,1,n)
{
int c;
scanf("%d",&w[i]);
c=w[i],sum+=c;
if(i!=1)
{
a1[i]=++l;
a[l]=mo-1;
l+=c;
a[l]=1,sz[i]=c,sm[i]=sz[i]+sm[i-1];
}
}
wg[0]=1;
LL v=ksm(3,(mo-1)/M);
fo(i,1,M) wg[i]=wg[i-1]*v%mo;
doit(2,n);
LL ans=0;
fo(i,0,sm[n])
ans=(ans+a[i]*(LL)sum%mo*ksm(sum-i,mo-2)%mo+mo)%mo;
printf("%lld\n",ans*w[1]%mo*(LL)ksm(sum,mo-2)%mo);
}

【杂题】[LibreOJ 2541] 【PKUWC2018】猎人杀【生成函数】【概率与期望】的更多相关文章

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

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

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

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

  3. [PKUWC2018]猎人杀

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

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

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

  5. LOJ 2541 「PKUWC2018」猎人杀——思路+概率+容斥+分治

    题目:https://loj.ac/problem/2541 看了题解才会……有三点很巧妙. 1.分母如果变动,就很不好.所以考虑把操作改成 “已经选过的人仍然按 \( w_i \) 的概率被选,但是 ...

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

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

  7. [LOJ2541] [PKUWC2018] 猎人杀

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

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

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

  9. 题解-PKUWC2018 猎人杀

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

随机推荐

  1. 在 macOS 中激活 Astash Professional

    Astah Professional v7.2.0-1ff236版安装完毕后,直接用压缩包内的 astah-pro.jar 替换原安装目录内的同名文件(/Applications/astah prof ...

  2. http://4526621.blog.51cto.com/4516621/1343369

    http://4526621.blog.51cto.com/4516621/1343369

  3. Python中ndarray数组切片问题a[-n -x:-y]

    先看看如下代码: >>a=np.arange(10)>>a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>>a[-7:] array( ...

  4. 07Mendel's First Law

    Problem Figure 2. The probability of any outcome (leaf) in a probability tree diagram is given by th ...

  5. Nginx搭建后,图片存储在Tomcat上,前端无法回显图片问题

    一.Nginx与Tomcat连接搭建的环境,Nginx设置了前端的访问路径为 (1)前端代码配置: root /usr/local/nginx/html; index index.html index ...

  6. cordova/webapp/html5 app 用corsswalk替换内核,优化安卓webview

    Crosswalk与WebView的不同 为什么要用corsswalk?由于cordova应用在安卓上运行的时候,都是调用的手机webview,而在不同的安卓机.不同版本的系统上,webview的性能 ...

  7. [label][转载][web-design-psychology]网页设计心理

    原文出处: http://mux.alimama.com/posts/1301 Tip1:信息不要同时全部展示,阶段性地向用户展示当前场景里必要的信息 设计师经常犯的错误:同时将大量信息展示给用户.不 ...

  8. Objective-C 学习笔记(四) 数组

    Objective-C 数组作为函数参数传递 如果想在一个函数作为参数,通过一维数组,就必须声明函数形式参数 方式一    指针作为形式参数 - (void) myFunction(int *) pa ...

  9. Devexpress treelist 控件属性大全

    属性列表 1.OptionsSelection: EnableAppearanceForcusedCell:选中的Cell的Appearance设置是否可用.默认为True: EnableAppear ...

  10. log4net 日志打印不全

    程序用的是log4net打印日志,偶现日志打印不全的问题,程序的log4net配置如下: <log4net> <root> <level value="ALL& ...