LOJ #2541「PKUWC2018」猎人杀
这样$ PKUWC$就只差一道斗地主了
假装补题补完了吧.....
这题还是挺巧妙的啊......
题意
每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \frac{a_i}{a_{alive}}$,求第一个人最后死的概率
数据范围:$ 1 \leq a_i \leq 10^5,\sum\limits_{i=1}^n a_i \leq 10^5$
$Solution$
以下部分用$ val$表示所有人的嘲讽值之和
先讲讲$ n*val$的$ DP$
用$ P_S$表示集合$ S$中的人都在$ 1$后面死的概率
由于期间打死其他人不会影响$ P_S$的结果
每个$ P_S$是独立的
等价与下一枪打在$ S$或$1$上打死$1$的概率即$ \frac{a_i}{a_S+a_i}$
其中$ a_S$表示集合$ S$的嘲讽值之和
则容斥计算答案为$ \sum\limits(-1)^{|S|+1}P_S$
容易发现枚举集合的复杂度过大无法承受
发现$ val$不大
尝试用$ f_{i,j}$表示前$ i$个人(从2开始枚举)嘲讽值之和为$ j$的方案数
发现有容斥系数不能直接记录方案
不过没有关系,由于容斥系数只和奇偶性有关,我们只需要把$ f_{i,j}$改成嘲讽值之和为$j$的系数和即可
转移的时候分选$ i$和不选$i$两种
如果选了前面的奇偶性会全部改变
因此得出转移方程式$ f_{i,j}=f_{i-1,j}-f_{i-1,j-a[i]}$
可以过$ 50$分
考虑生成函数
发现转移的本质是若干个形如$ (1-x^{a_i})$的二项式相乘
即最终转移结果为 $\prod\limits_{i=2}^n 1-x^{a_i}$
用$ NTT$分治计算这个过程
由于类似线段树结构的分治只有$ log_n$层,每层的复杂度是$ O(val \ log_{val})$
因此总复杂度是$ O(val \ log_n \ log_{val})$的,可以通过本题
以及还有$一个log$的小$ trick$

暂时还不会....以后再写吧
$update$
尝试去写了一下,好像比$ log^2$的分治慢啊....代码太丑就不贴了...Exp常数真大...
$ my \ code:$
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define p 998244353
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x = ; char zf = ; char ch = getchar();
while (ch != '-' && !isdigit(ch)) ch = getchar();
if (ch == '-') zf = -, ch = getchar();
while (isdigit(ch)) x = x * + ch - '', ch = getchar(); return x * zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int i,j,k,m,n,x,y,z,cnt;
int a[];
int ksm(int x,int y){
int ans=;
for(rt i=y;i;i>>=,x=1ll*x*x%p)if(i&)ans=1ll*ans*x%p;
return ans;
}
namespace poly{
vector<int>R;
void getR(int n){
R.resize(n);
for(rt i=;i<n;i++)R[i]=(R[i>>]>>)|(i&)*(n>>);
}
void NTT(int n,vector<int>&A,int fla){
for(rt i=;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]);
for(rt i=;i<n;i<<=){
int w=ksm(,(p-)//i);
for(rt j=;j<n;j+=i<<){
int K=;
for(rt k=;k<i;k++,K=1ll*K*w%p){
int x=A[j+k],y=1ll*K*A[i+j+k]%p;
A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p;
}
}
}
if(fla==-){
reverse(A.begin()+,A.end());int invn=ksm(n,p-);
for(rt i=;i<n;i++)A[i]=1ll*A[i]*invn%p;
}
}
}
using namespace poly;
int calc(int L,int R,vector<int>&A){
if(L==R){
A.resize(a[L]+);
A[]=;A[a[L]]=-;
return a[L];
}
const int mid=L+R>>;
vector<int>f,g;
int len=calc(L,mid,f)+calc(mid+,R,g);
int lim=;while(lim<=len)lim<<=;
getR(lim);f.resize(lim);g.resize(lim);A.resize(lim);
NTT(lim,f,);NTT(lim,g,);
for(rt i=;i<lim;i++)A[i]=1ll*f[i]*g[i]%p;
NTT(lim,A,-);
return len;
}
int main(){
n=read();
for(rt i=;i<=n;i++)a[i]=read();
vector<int>xs;
int sum=calc(,n,xs);int ans=;
for(rt i=;i<=sum;i++)(ans+=1ll*xs[i]*ksm(i+a[],p-)%p*a[]%p)%=p;
cout<<(ans+p)%p;
return ;
}
LOJ #2541「PKUWC2018」猎人杀的更多相关文章
- LOJ 2541 「PKUWC2018」猎人杀——思路+概率+容斥+分治
题目:https://loj.ac/problem/2541 看了题解才会……有三点很巧妙. 1.分母如果变动,就很不好.所以考虑把操作改成 “已经选过的人仍然按 \( w_i \) 的概率被选,但是 ...
- loj#2541. 「PKUWC2018」猎人杀
传送门 思路太清奇了-- 考虑容斥,即枚举至少有哪几个是在\(1\)号之后被杀的.设\(A=\sum_{i=1}^nw_i\),\(S\)为那几个在\(1\)号之后被杀的人的\(w\)之和.关于杀了人 ...
- 【LOJ】#2541. 「PKUWC2018」猎人杀
题解 一道神仙的题>< 我们毙掉一个人后总的w的和会减少,怎么看怎么像指数算法 然而,我们可以容斥-- 设\(\sum_{i = 1}^{n} w_{i} = Sum\) 我们把问题转化一 ...
- 「PKUWC2018」猎人杀
「PKUWC2018」猎人杀 解题思路 首先有一个很妙的结论是问题可以转化为已经死掉的猎人继续算在概率里面,每一轮一直开枪直到射死一个之前没死的猎人为止. 证明,设所有猎人的概率之和为 \(W\) , ...
- [LOJ2541]「PKUWC2018」猎人杀
loj description 有\(n\)个猎人,每个猎人有一个仇恨度\(w_i\),每个猎人死后会开一枪打死一个还活着的猎人,打中每个猎人的概率与他的仇恨度成正比. 现在你开了第一枪,打死每个猎人 ...
- loj2541 「PKUWC2018」猎人杀 【容斥 + 分治NTT】
题目链接 loj2541 题解 思路很妙啊, 人傻想不到啊 觉得十分难求,考虑容斥 由于\(1\)号可能不是最后一个被杀的,我们容斥一下\(1\)号之后至少有几个没被杀 我们令\(A = \sum\l ...
- LOJ2541. 「PKUWC2018」猎人杀 [概率,分治NTT]
传送门 思路 好一个神仙题qwq 首先,发现由于一个人死之后分母会变,非常麻烦,考虑用某种方法定住分母. 我们稍微改一改游戏规则:一个人被打死时只打个标记,并不移走,也就是说可以被打多次但只算一次.容 ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
随机推荐
- saltstack常用命令
Salt通过公钥加密和认证minions.想要让minion从master端接受命令,minions的密钥需要被master接受 salt-key -L #列出master上的密钥; salt-key ...
- Python函数--装饰器进阶
开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...
- windows c语言 网络
WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(2, 2); err = WSAStart ...
- 第十二节,TensorFlow读取数据的几种方法以及队列的使用
TensorFlow程序读取数据一共有3种方法: 供给数据(Feeding): 在TensorFlow程序运行的每一步, 让Python代码来供给数据. 从文件读取数据: 在TensorFlow图的起 ...
- function call操作符(operator()) 仿函数(functor)
主要是需要某种特殊的东西来代表一整组操作 代表一整组操作的当然是函数,过去通过函数指针实现 所以STL算法的特殊版本所接受的所谓条件或策略或一整组操作都以仿函数的形式呈现 #include <i ...
- cookie猜数字游戏(上)---------------思路分析(踩坑)
说明:用户第一次请求页面的时候,同时会产生一个随机数,用户点提交表单的时候,会将输入的数字与第一次请求产生的数字进行一个对比. 问题一:如何保存用户每次提交的数据 我们常见的在服务器中保存数据的方式是 ...
- thinkphp 攻略
php框架 一.真实项目开发步骤: 多人同时开发项目,协作开发项目.分工合理.效率有提高(代码风格不一样.分工不好) 测试阶段 上线运行 对项目进行维护.修改.升级(单个人维护项目,十分困难, ...
- bzoj2434 fail树 + dfs序 + 树状数组
https://www.lydsy.com/JudgeOnline/problem.php?id=2434 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现, ...
- Windows server 2008 R2远程桌面3389端口号修改
修改 Windows 服务器默认远程端口 https://help.aliyun.com/document_detail/51644.html?spm=5176.doc51644.6.784.4iAH ...
- Kafka技术内幕 读书笔记之(五) 协调者——消费组状态机
协调者保存的消费组元数据中记录了消费组的状态机 , 消费组状态机的转换主要发生在“加入组请求”和“同步组请求”的处理过程中 .协调者处理“离开消费组请求”“迁移消费组请求”“心跳请求” “提交偏移量请 ...