【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. c语言数字图像处理(四):灰度变换

    灰度变换 灰度变换函数 s = T(r)   其中r为输入图像在(x, y)点处的灰度值,s为输出图像在(x, y)点处的灰度值 灰度变换的作用 上图所示的两幅T(s)函数的图像曲线,第一幅图可以增强 ...

  2. could not launch process: decoding dwarf section info at offset 0x0: too short

    Fabric调试异常 作者在使用chaincode进行智能合约开发的过程中,使用Goland + Golang + win10_X64作为开发环境: GoLand 2018.1.4 Build #GO ...

  3. ovs源码阅读--元组空间搜索算法

    关于TTS(元组空间搜索算法)的详细介绍可以参考OVS+DPDK Datapath 包分类技术这篇文章,本文只对该篇博客进行简单的介绍,案例和部分图片来自于OVS+DPDK Datapath 包分类技 ...

  4. 不用U盘,用一台好电脑给另一个电脑重装windows10

    先把坏电脑硬盘拆下来,然后挂到好电脑上 把这块盘用系统的磁盘管理工具改成GPT分区表格式,然后整盘分区(NTFS). 再对这个分区进行压缩卷操作,分出第二个区(FAT32格式 大小大于5G 我这里用了 ...

  5. 精通Python爬虫-03-狩猎大师

    声明: 本系列文章原创于慕课网,作者秋名山车神,任何人不得以任何形式在不经作者允许的情况下,进行任何形式的印刷以及销售,转载需注明出处及此声明. 本系列文章更新至少每周一更,将涉及Python爬虫基础 ...

  6. plsql 不修改tnsnames.ora文件

    PLSQL 不修改tnsname直接连数据库的方式在PLSQL的Database中直接输入192.168.1.6:1521/VP.其中192.168.1.6为数据库的IP:1521为数据库端口:VP为 ...

  7. 数据库——SQL数据定义

    数据定义  SQL的数据定义语句 操 作 对 象 操  作  方  式 创  建 删  除 修  改 表 CREATE TABLE DROP TABLE ALTER TABLE 视  图 CREATE ...

  8. [2017BUAA软工]结对项目:数独扩展

    结对项目:数独扩展 1. Github项目地址 https://github.com/Slontia/Sudoku2 2. PSP估计表格 3. 关于Information Hiding, Inter ...

  9. VS2010+WinXP+MFC程序 无法定位程序输入点于动态链接库

    1.问题描述 原开发环境:Win7 64位旗舰版,VS2010,ThinkPad T460 出现问题:自己开发的MFC程序在WinXP环境下无法正常运行,弹框“无法定位程序输入点InitializeC ...

  10. DataTime日期格式化

    C# DateTime日期格式化 在C#中DateTime是一个包含日期.时间的类型,此类型通过ToString()转换为字符串时,可根据传入给Tostring()的参数转换为多种字符串格式. 目录 ...