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

题面

LOJ

题解

这题好神仙啊。

直接考虑概率很麻烦,因为分母总是在变化。

但是,如果一个人死亡之后,我们不让他离场,假装给他打一个标记(猎人印记???)

如果在一次选择的时候选中了一个已经被打过标记的人,那么我们就重新做一次选择。

这样显然没有任何影响。

现在考虑如何求第一个人最后一个被打上标记的概率。

我们容斥一下,枚举一下哪些人会在\(1\)之后被选择,那么容斥系数就是\((-1)\)的人数次方。

那么对于钦定的在\(1\)之后被选择的集合\(S\),假设他们的\(w\)的和为\(S\),所有人\(w\)的和为\(A\)。这个集合贡献的值就是\((-1)^{|S|}\sum_{i=1}^{\infty}(1-\frac{S+W_1}{A})^i\frac{W_1}{A}\)。后面的部分可以化简,结果就是\(\frac{W_1}{S+W_1}\)。

现在的问题就是求\(S\)了。

我们发现因为是一个分数的形式,如果直接计算显然是不能够直接\(dp\)。

换种思路,如果我们计算每一种分母分别出现了多少次,这个就非常好算了。

这样就可以通过\(dp\)计算,同时发现事实上这个\(dp\)就是一个\(01\)背包,所以可以用分治+\(NTT\)来优化计算。

时间复杂度\(O(nlogn^2)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define MAX 250000
#define ll long long
#define MOD 998244353
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int n,w[MAX],ans;
int W[MAX],r[MAX];
void NTT(int *P,int len,int opt)
{
int N,l=0;for(N=1;N<len;N<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
{
int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
{
int X=P[j+k],Y=1ll*P[i+j+k]*W[k]%MOD;
P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
}
}
if(opt==-1)
{
reverse(&P[1],&P[N]);
for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
}
}
int tmp[50][MAX];
int S[MAX],top,P[MAX];
int Solve(int l,int r,int *P)
{
if(l==r){P[0]=1;P[w[l]]=MOD-1;return w[l];}
int mid=(l+r)>>1,l1,l2,ls,rs,N;
ls=S[top--];l1=Solve(l,mid,tmp[ls]);
rs=S[top--];l2=Solve(mid+1,r,tmp[rs]);
for(N=1;N<=l1+l2;N<<=1);
NTT(tmp[ls],N,1);NTT(tmp[rs],N,1);
for(int i=0;i<N;++i)P[i]=1ll*tmp[ls][i]*tmp[rs][i]%MOD;
NTT(P,N,-1);S[++top]=ls;S[++top]=rs;
for(int i=0;i<N;++i)tmp[ls][i]=tmp[rs][i]=0;
return l1+l2;
}
int main()
{
n=read();
for(int i=1;i<=n;++i)w[i]=read();
for(int i=0;i<50;++i)S[++top]=i;
int len=Solve(2,n,P);
for(int i=0;i<=len;++i)ans=(ans+1ll*P[i]*fpow(w[1]+i,MOD-2))%MOD;
ans=1ll*ans*w[1]%MOD;
printf("%d\n",ans);
return 0;
}

【LOJ2541】【PKUWC2018】猎人杀(容斥,FFT)的更多相关文章

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

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

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

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

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

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

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

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

  5. [LOJ2541] [PKUWC2018] 猎人杀

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

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

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

  7. UVa12633 Super Rooks on Chessboard(容斥 + FFT)

    题目 Source http://acm.hust.edu.cn/vjudge/problem/42145 Description Let’s assume there is a new chess ...

  8. UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...

  9. [PKUWC2018]猎人杀

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

  10. 题解-PKUWC2018 猎人杀

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

随机推荐

  1. OpenGL学习笔记(3) 纹理

    关于纹理 一般游戏里的物体不一定都是纯色的物体,物体上面会有一些图片贴在上面,比如墙壁,箱子,地板,可以看到砖头.木板和大理石组成的图片,要把图片贴到计算机里的几何图形的话,就要把图片的颜色采样贴到几 ...

  2. [文章存档]Kudu 的 Debug Console 窗口如何查看更多文件

    链接:https://docs.azure.cn/zh-cn/articles/azure-operations-guide/app-service-web/aog-app-service-web-h ...

  3. Codeforces1084 | Round526Div2 | 瞎讲报告

    目录 A. The Fair Nut and Elevator B.Kvass and the Fair Nut C.The Fair Nut and String D.The Fair Nut an ...

  4. webbrowser 模块的 open()方法

    webbrowser 模块的 open()函数可以启动一个新浏览器,打开指定的 URL.在交 互式环境中输入以下代码: >>> import webbrowser >>& ...

  5. python os.walk详解

    os模块大全详情 os.walkos.walk方法,主要用来遍历一个目录内各个子目录和子文件. os.walk(top, topdown=True, onerror=None, followlinks ...

  6. Python交互数据库(Mysql | Mongodb | Redis)

    数据库 Mysql Mysql MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于Oracle旗下产品 MyS ...

  7. Vue实现双向绑定的原理以及响应式数据

    一.vue中的响应式属性 Vue中的数据实现响应式绑定 1.对象实现响应式: 是在初始化的时候利用definePrototype的定义set和get过滤器,在进行组件模板编译时实现water的监听搜集 ...

  8. 在Web Page中包含PHP代码

    PHP代码可以出现在Web Page的任何位置,甚至在HTML的标签里面也可以.有4中方式在Web Page中包含PHP代码: 使用<?php ... ?>标签 <!doctype ...

  9. Scrum Meeting 5 -2014.11.11

    放假过掉一大半.大家都努力赶着进度,算法实现基本完成.可能还有些细小的改动,但也可以统一进入测试阶段了. 今天叫了部分在校人员开了个小会.任务决定以测试为主,同时开始进行服务器的部署. 在之前尝试服务 ...

  10. 第一个scrim任务分布

    一.项目经理:郭健豪 二.scrim分工 杨广鑫.郭健豪:制作第一个精选页面布局,和代码实现.如:实现图书推荐布局中图书的排布,搜索框代码的实现,消息提示的跳转 李明.郑涛:实现第一个精选页面数据库的 ...