传送门

思路

好一个神仙题qwq

首先,发现由于一个人死之后分母会变,非常麻烦,考虑用某种方法定住分母。

我们稍微改一改游戏规则:一个人被打死时只打个标记,并不移走,也就是说可以被打多次但只算一次。容易发现这并不影响最终结果。

然而光想到这个好像没什么用?

再考虑容斥:枚举哪些人在1之后被打死,其他随意。设在1后面的人的权值为\(S\),总权值为\(sum\),那么概率就是

\[\begin{align*}
&\sum_{i=0}^{\infty} (1-\frac{w_1+S}{sum})^i\frac{w_1}{sum}\\
=&\frac{w_1}{sum}\times \frac{sum}{S+w_1}\\
=&\frac{w_1}{w_1+S}
\end{align*}
\]

(上式表示枚举打了几枪之后打到1)

而容斥系数是\((-1)^{人数}\)。

由于\(\sum w\)很小,可以考虑背包算出\(S\)的贡献,但跑不过去。

用分治NTT优化背包即可,每个人的生成函数是\(1-x^{w_i}\),对应每多一个人容斥系数就乘\(-1\)。

代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 404004
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; int r[sz],limit;
void NTT_init(int n)
{
int l=-1;
for (limit=1;limit<=n;limit<<=1) ++l;
rep(i,0,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<l);
}
void NTT(ll *a,int type)
{
rep(i,0,limit-1) if (i<r[i]) swap(a[i],a[r[i]]);
for (int mid=1;mid<limit;mid<<=1)
{
ll Wn=ksm(3,(mod-1)/mid>>1);if (type==-1) Wn=inv(Wn);
for (int len=mid<<1,j=0;j<limit;j+=len)
{
ll w=1;
for (int k=0;k<mid;k++,w=w*Wn%mod)
{
ll x=a[j+k],y=w*a[j+k+mid]%mod;
a[j+k]=(x+y)%mod;a[j+k+mid]=(x-y+mod)%mod;
}
}
}
if (type==1) return;
ll I=inv(limit);
rep(i,0,limit-1) a[i]=a[i]*I%mod;
} int n;
int w[sz]; ll tmp[60][sz];
int st[60],top;
int len[60];
int work(int l,int r)
{
if (l==r){int k=st[top--];tmp[k][0]=1;tmp[k][w[l]]=mod-1;len[k]=w[l];return k;}
int mid=(l+r)>>1,L=work(l,mid),R=work(mid+1,r);
int k=st[top--];
NTT_init(len[L]+len[R]+2);
NTT(tmp[L],1);NTT(tmp[R],1);
rep(i,0,limit-1) tmp[L][i]=tmp[L][i]*tmp[R][i]%mod;
NTT(tmp[L],-1);
rep(i,0,len[L]+len[R]) tmp[k][i]=tmp[L][i];
len[k]=len[L]+len[R];
rep(i,0,limit-1) tmp[L][i]=tmp[R][i]=0;
st[++top]=L;st[++top]=R;
return k;
} int main()
{
file();
read(n);
int sum=0;
rep(i,1,n) read(w[i]),sum+=w[i];
rep(i,1,50) st[++top]=i;
int k=work(2,n);
ll ans=0;
rep(i,0,sum-w[1]) (ans+=tmp[k][i]*inv(w[1]+i)%mod)%=mod;
ans=ans*w[1]%mod;
cout<<ans;
return 0;
}

LOJ2541. 「PKUWC2018」猎人杀 [概率,分治NTT]的更多相关文章

  1. loj2541 「PKUWC2018」猎人杀 【容斥 + 分治NTT】

    题目链接 loj2541 题解 思路很妙啊, 人傻想不到啊 觉得十分难求,考虑容斥 由于\(1\)号可能不是最后一个被杀的,我们容斥一下\(1\)号之后至少有几个没被杀 我们令\(A = \sum\l ...

  2. [LOJ2541]「PKUWC2018」猎人杀

    loj description 有\(n\)个猎人,每个猎人有一个仇恨度\(w_i\),每个猎人死后会开一枪打死一个还活着的猎人,打中每个猎人的概率与他的仇恨度成正比. 现在你开了第一枪,打死每个猎人 ...

  3. 「PKUWC2018」猎人杀

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

  4. 【LOJ】#2541. 「PKUWC2018」猎人杀

    题解 一道神仙的题>< 我们毙掉一个人后总的w的和会减少,怎么看怎么像指数算法 然而,我们可以容斥-- 设\(\sum_{i = 1}^{n} w_{i} = Sum\) 我们把问题转化一 ...

  5. loj#2541. 「PKUWC2018」猎人杀

    传送门 思路太清奇了-- 考虑容斥,即枚举至少有哪几个是在\(1\)号之后被杀的.设\(A=\sum_{i=1}^nw_i\),\(S\)为那几个在\(1\)号之后被杀的人的\(w\)之和.关于杀了人 ...

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

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

  7. LOJ #2541「PKUWC2018」猎人杀

    这样$ PKUWC$就只差一道斗地主了 假装补题补完了吧..... 这题还是挺巧妙的啊...... LOJ # 2541 题意 每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \fr ...

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

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

  9. loj2541【PKUWC2018】猎人杀

    题解 题目中的选择条件等价于正常选择所有猎人,而如果选到已经出局的猎人就继续选: 这两种选法是一样的因为(设$W=\sum_{i=1}^{n}w_{i}$ , $X$为已经出局的猎人的$w$之和): ...

随机推荐

  1. Nokia5130不能上网

    说明 我是一个挺怀旧的人,一直想入手一个好几年前买的Nokia5130. 于是昨天在淘宝上买了一个,花了我一百多.不过早就停产了,买到的自然是翻新机. 收到货的时候,看似一切美好,但是下载了个uc的j ...

  2. 【Linux】Shell批量修改文件名

    修改文件名,替换中间字符: 例如:ABC_define_EFG.jpg,要把中间的define替换成argument: 用如下脚本即可: for var in *; do mv "$var& ...

  3. 记录一次kafka解决相同userId顺序消费的问题

    基本思路:在kafka生产者生产消息时,把相同userId的消息落在同一个分区/partition public void sendTopic1(String tpoic, String userId ...

  4. Go part 7 反射,反射类型对象,反射值对象

    反射 反射是指在程序运行期间对程序本身进行访问和修改的能力,(程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时,程序无法获取自身的信息) 支持反射的语言可以在程序编 ...

  5. 解决github提示安全漏洞的问题

    今天在提交代码的时候发现github提示了这样的错误: We found potential security vulnerabilities in your dependencies. Only t ...

  6. js中的深复制与浅复制

    前言 所谓深复制与浅复制(深拷贝与浅拷贝),乍一听感觉听高大上,像是一个非常难理解的概念,其实我们平常项目开发都是在用的,只是你可能不知道该怎么叫它的名字而已,就像你听熟了一首歌,就是不知道这首歌叫什 ...

  7. 【leetcode】544. Output Contest Matches

    原题 During the NBA playoffs, we always arrange the rather strong team to play with the rather weak te ...

  8. 布隆过滤算法体会(BlooomFilter)

    在一个m位的位数组里,一个字符串经过k次hash随机分布到k个位置. http://www.cnblogs.com/aspnethot/articles/3442813.html 布隆filter数据 ...

  9. 数据库管理工具-Navicat Premium 12

    首先感谢下github上大佬,我才能使用这个软件.也可以直接浏览https://github.com/DoubleLabyrinth/navicat-keygen进行安装,非常详细. 1.https: ...

  10. Nginx.conf配置文件默认配置块略解

    #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #erro ...