loj

description

有\(n\)个猎人,每个猎人有一个仇恨度\(w_i\),每个猎人死后会开一枪打死一个还活着的猎人,打中每个猎人的概率与他的仇恨度成正比。

现在你开了第一枪,打死每个猎人的概率同样也和它的仇恨度成正比。现在第一个猎人想知道他最后一个死的概率。

\(w_i>0,\sum w_i\le10^5\),模\(998244353\)

sol

容斥,考虑强制某个集合内的猎人在一号猎人之后被打死,剩下的猎人无所谓。

设这个集合内的猎人的仇恨度之和是\(W\),所有猎人的仇恨度之和是\(Sum\),那么这个集合对答案的贡献就是:$$\sum_{i=0}{\inf}(1-\frac{W+w_1}{Sum})i\frac{w_1}{Sum}=\frac{w_1}{W+w_1}$$

我们可以把“在剩下还活着的人中选一个打死”改为“在所有人中选一个打,直至打到一个活着的人”,这样每个人被打到的概率就始终都是\(\frac{w_i}{Sum}\),只不过开枪次数就没有了上限。不过显然这个无限等比数列是很容易进行求和的。

所以上面的式子的意思是:枚举前\(i\)枪都没有打中一号猎人和选中集合中的猎人,而接下来一枪刚好把一号猎人打死的概率。

于是现在关键在于枚举集合。我们发现对于\(W\)相同的集合可以一起计算,而\(W\)不同的集合至多只有\(O(n)\)个,所以可以枚举\(W\),计算有多少个集合的仇恨度之和为\(W\)。这里同时也要乘上容斥系数\(1\)或\(-1\)。

其实要计算的就是一个这样的东西:$$\prod_{i=2}{n}1-x{w_i}$$

所以直接分治\(NTT\)就行了。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 4e5+5;
const int mod = 998244353;
int n,w[N],s[N],inv[N],tmp[50][N],Stack[50],top,rev[N],og[N],ans;
inline void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
inline int fastpow(int a,int b){
int res=1;
while(b){if(b&1)res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
return res;
}
void ntt(int *P,int opt,int len){
int l=0;while((1<<l)<len)++l;--l;
for (int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
for (int i=0;i<len;++i) if (i<rev[i]) swap(P[i],P[rev[i]]);
for (int i=1;i<len;i<<=1){
int W=fastpow(3,(mod-1)/(i<<1));
if (opt==-1) W=fastpow(W,mod-2);
og[0]=1;for (int j=1;j<i;++j) og[j]=1ll*og[j-1]*W%mod;
for (int p=i<<1,j=0;j<len;j+=p)
for (int k=0;k<i;++k){
int x=P[j+k],y=1ll*og[k]*P[j+k+i]%mod;
P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod;
}
}
if (opt==-1) for (int i=0,Inv=fastpow(len,mod-2);i<len;++i) P[i]=1ll*P[i]*Inv%mod;
}
void solve(int *P,int l,int r){
if (l==r) {P[0]=1;P[w[l]]=mod-1;return;}
int mid=l+r>>1,ls=Stack[top--];
solve(tmp[ls],l,mid);
int rs=Stack[top--];
solve(tmp[rs],mid+1,r);
int len=1;while(len<=s[r]-s[l-1])len<<=1;
ntt(tmp[ls],1,len);ntt(tmp[rs],1,len);
for (int i=0;i<len;++i) P[i]=1ll*tmp[ls][i]*tmp[rs][i]%mod;
ntt(P,-1,len);
Stack[++top]=ls;Stack[++top]=rs;
for (int i=0;i<len;++i) tmp[ls][i]=tmp[rs][i]=0;
}
int main(){
n=gi();inv[0]=inv[1]=1;
for (int i=1;i<=n;++i) w[i]=gi(),s[i]=s[i-1]+w[i];
for (int i=2;i<=s[n];++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
for (int i=1;i<50;++i) Stack[++top]=i;
solve(tmp[0],2,n);
for (int i=0;i<=s[n]-s[1];++i) add(ans,1ll*w[1]*inv[i+w[1]]%mod*tmp[0][i]%mod);
printf("%d\n",ans);
return 0;
}

[LOJ2541]「PKUWC2018」猎人杀的更多相关文章

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

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

  2. LOJ2541. 「PKUWC2018」猎人杀 [概率,分治NTT]

    传送门 思路 好一个神仙题qwq 首先,发现由于一个人死之后分母会变,非常麻烦,考虑用某种方法定住分母. 我们稍微改一改游戏规则:一个人被打死时只打个标记,并不移走,也就是说可以被打多次但只算一次.容 ...

  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」猎人杀

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

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

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

  8. loj2541【PKUWC2018】猎人杀

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

  9. LOJ #2541. 「PKUWC 2018」猎人杀(容斥 , 期望dp , NTT优化)

    题意 LOJ #2541. 「PKUWC 2018」猎人杀 题解 一道及其巧妙的题 , 参考了一下这位大佬的博客 ... 令 \(\displaystyle A = \sum_{i=1}^{n} w_ ...

随机推荐

  1. Java文件IO流的操作总结

    Java中的IO操作涉及到的概念及相关类很多,很容易弄混,今天特来整理总结一下,并附上一份完整的文件操作的代码. 概念解析 读和写 流就是管道,向管道里面写数据用输出流:write 从管道里面读数据, ...

  2. 一个很大的文件,存放了10G个整数的乱序数列,如何用程序找出中位数。

    一.梳理审题 一.看清题目: 注意这个题目的量词,这个文件中有10G个整数,而不是这个文件占了10G的内存空间. 二.一些疑问: 在计算机中我们讲的G.M等都是存储容量的概念,但是一般都会在会面加上B ...

  3. Mail.Ru Cup 2018 Round 3 Solution

    A. Determine Line Water. #include <bits/stdc++.h> using namespace std; ]; int main() { while ( ...

  4. c++第二十七天

    p135~p140:1.位运算符.作用于整数类型的运算对象,并把运算对象看成是二进制的集合,提供检查和设置二进制位的功能. 2.bitest:一种可表示任意大小的二进制位集合的标准库类型. 3.关于符 ...

  5. openwrt下使用wget出现Failed to allocate uclient context

    一.场景重现 root@OpenWrt:/# wget www.baidu.com Downloading 'www.baidu.com' Failed to allocate uclient con ...

  6. FZU 1901 Period II(KMP中的next)题解

    题意:给你一串字符串,问你前后缀相同情况有几种,并输出后缀位置(?这里一直没看懂length是什么,但是这样理解答案也对,然后还要加上本身长度) 思路:这里好好讲讲next的用法.我们都知道next代 ...

  7. [问题解决]不使用PWM调速系统,彻底解决一个L298N带动两个电机却转速不同的问题

    问题描述:由单片机的VCC引脚供电,使用L298N控制两个电机,发现左右两个轮子的转速老是不一样,更多的情况是左轮转速高(左轮电机接OUT1和OUT2),右轮转速低(右轮电机接OUT3和OUT4)甚至 ...

  8. atcoder ARC092 D - Two Sequences 二分 & 二进制

    今天生日捏,嘻嘻~ 题意:给定A B数组长度为n 求所有 (1<=i,j <=n ) a[i]+b[j] 的异或和. n <=200000  ai bi <=228 这题比赛没 ...

  9. JS+Canvas的棋盘游戏和Java的动态结合

    二维数组的题做了有几个了,感觉很有趣,随后想到想做一个五子棋的游戏. 因为前端知识匮乏,但感觉只是Java中去用二维数组做的话还是不太难的. 首先生成15*15的棋盘,(先不考虑前后端交互),其后Ha ...

  10. IDEA 搭建授权服务器

    引用地址  http://blog.lanyus.com/archives/317.html 今天突出发现基本公开的激活地址都被屏蔽了(IDEA 2017.3 版本) 记录一下 docker pull ...