「PKUWC2018」猎人杀

解题思路

首先有一个很妙的结论是问题可以转化为已经死掉的猎人继续算在概率里面,每一轮一直开枪直到射死一个之前没死的猎人为止。

证明,设所有猎人的概率之和为 \(W\) ,当前已经死掉了概率之和为 \(T\) 的猎人,原问题下一个射死 \(i\) 的概率 \(P\) 为

\[P =\dfrac{w_i}{W-T}
\]

转化过后的问题下一个射死 \(i\) 的概率为

\[P=\dfrac{T}{W}P+\dfrac{w_i}{W} \\
\dfrac{W-T}{W}P=\dfrac{w_i}{W} \\
P=\dfrac{w_i}{W-T}
\]

两个问题的概率是一样的。

然后考虑经典容斥,钦定一个不包含 \(1\) 的猎人集合 \(S\) 在 \(1\) 之后被射死,用 \(sum(S)\) 表示这个猎人集合的 \(w_i\) 之和,那么答案就是:

\[Ans =\sum_S (-1)^{|S|}\sum_{i=0}^{\infty} (1-\frac{sum(S)+w_1}{W})^i\frac{w_1}{W}\\
\]

考虑到 \(\sum_{i=0}^{\infty}(1-\dfrac{sum(S)+w_1}{W})^i\) 是收敛的,所以

\[Ans =\sum _{S}(-1)^{|S|}\frac{W}{sum(S)+w_1}\times \frac{w_1}W{}\\
Ans = w_1\sum _{S}\dfrac{(-1)^{|S|}}{sum(S)+w_1}
\]

构造生成函数 \([x^n]F(x)\) 为 \(sum(S)=n\) 的所有方案的 \((-1)^{|S|}\) 之和,那么有

\[F(x)=\prod_{i=2}^n(1-x^{w_i}) \\
Ans = w_1\sum_{i=0}^{W-w_1}\dfrac{[x^i]F(x)}{i+w_1}
\]

因为 \(\sum w_i\) 不大,分治 NTT 求解即可,复杂度 \(\mathcal O(n \log^2 n)\),可以对这个式子 \(\ln\) 一下再考虑泰勒展开形式把有用的项记下来 \(\exp\) 回去,估计跑不过两个 \(\log\)。

code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = (1 << 21), P = 998244353, G = 3;
namespace poly{
int rev[N], len, lg;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % P)
if(b & 1) ans = 1ll * ans * a % P;
return ans;
}
inline void timesinit(int lenth){
for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
for(int i = 0; i < len; i++)
rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1));
}
inline void DFT(int *a, int sgn){
for(int i = 0; i < len; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int k = 2; k <= len; k <<= 1){
int w = Pow(G, (P - 1) / k);
if(sgn == -1) w = Pow(w, P - 2);
for(int i = 0; i < len; i += k){
int now = 1;
for(int j = i; j < i + (k >> 1); j++){
int x = a[j], y = 1ll * now * a[j+(k>>1)] % P;
a[j] = x + y >= P ? x + y - P : x + y;
a[j+(k>>1)] = x - y < 0 ? x - y + P : x - y;
now = 1ll * now * w % P;
}
}
}
if(sgn == -1){
int INV = Pow(len, P - 2);
for(int i = 0; i < len; i++) a[i] = 1ll * a[i] * INV % P;
}
}
}
using poly::Pow;
using poly::DFT;
using poly::timesinit;
int a[N], b[N], w[N], n;
inline vector<int> solveNTT(int l, int r){
if(l == r){
vector<int> vec;
vec.resize(w[l] + 1), vec[0] = 1, vec[w[l]] = P - 1;
return vec;
}
int mid = (l + r) >> 1;
vector<int> A = solveNTT(l, mid);
vector<int> B = solveNTT(mid + 1, r);
int lenth = (int) A.size() + (int) B.size() - 1;
for(int i = 0; i < (int) A.size(); i++) a[i] = A[i];
for(int i = 0; i < (int) B.size(); i++) b[i] = B[i];
timesinit(lenth);
DFT(a, 1), DFT(b, 1);
for(int i = 0; i < poly::len; i++) a[i] = 1ll * a[i] * b[i] % P;
DFT(a, -1);
vector<int> vec;
for(int i = 0; i < lenth; i++) vec.push_back(a[i]);
for(int i = 0; i < poly::len; i++) a[i] = b[i] = 0;
return vec;
}
int main(){
read(n);
if(n == 1) return puts("1"), 0;
for(int i = 1; i <= n; i++) read(w[i]);
vector<int> ans = solveNTT(2, n);
int Ans = 0;
for(int i = 0; i < (int) ans.size(); i++)
(Ans += 1ll * ans[i] * Pow(i + w[1], P - 2) % P) %= P;
cout << 1ll * w[1] * Ans % P << endl;
return 0;
}

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

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

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

  2. [LOJ2541]「PKUWC2018」猎人杀

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

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

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

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

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

  5. LOJ #2541「PKUWC2018」猎人杀

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

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

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

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

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

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

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

  9. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

随机推荐

  1. Hadoop源码阅读-HDFS-day1

    HDFS声明及构造函数 @InterfaceAudience.Private @InterfaceStability.Evolving public class Hdfs extends Abstra ...

  2. ngx_lua_API 指令详解(六)ngx.thread.spawn、ngx.thread.wait、ngx.thread.kill介绍

    摘要:通过lua-nginx-module中的ngx.thread同时执行多个任务. ngx_lua中访问多个第三方服务 ngx_lua中提供了ngx.socket API,可以方便的访问第三方网络服 ...

  3. 一个由SEO优化展开的meta标签大讲解

    您的个人网站即使做得再精彩,在“浩瀚如海”的网络空间中,也如一叶扁舟不易为人发现,如何推广个人网站,人们首先想到的方法无外乎以下几种: ● 在搜索引擎中登录自己的个人网站 ● 在知名网站加入你个人网站 ...

  4. 浅说Get请求和Post请求

    Web 上最常用的两种 Http 请求就是 Get 请求和 Post 请求了.我们在做 java web 开发时,也总会在 servlet 中通过 doGet 和 doPost 方法来处理请求:更经常 ...

  5. 【转】在Mac OS X 10.8中配置Apache + PHP + MySQL

    CHENYILONG Blog 在Mac OS X 10.8中配置Apache + PHP + MySQL 在Mac OS X 10.8中配置Apache+PHP+MySQL的内容包括: 配置Apac ...

  6. iOS8 UICollectionView横向滑动demo

    在iOS8中,scrollView和加载在它上面的点击事件会有冲突,所以做一个横向滑动的界面最好的选择就是UICollectionView. 这个效果可以用苹果公司提供的官方demo修改而来,下载地址 ...

  7. lrc歌词文件格式

    一.lrc文件有什么作用 lrc文件就是一个文本文件,用来记录歌曲的歌词信息,使得播放歌曲时能够让歌词与声音同步显示,类似于电影字幕那种效果. 心情很丧时我们会听首歌陶冶一下情操,不知你是否注意过音乐 ...

  8. GBDT理解

    一.提升树 提升方法实际采用加法模型(即基函数的线性组合)与前向分布算法.以决策树为基函数的提升方法称为提升树,boosting tree.对分类问题的决策树是二叉分类树,对回归问题的决策树是二叉回归 ...

  9. JS种this的四种用法

    记住以下四点: 1.没调用对象就指向全局对象 2.有对象就指向调用对象 3.用new构造就指向新对象 4.通过 apply 或 call 或 bind 来改变 this 的所指. 1.测试一:没调用对 ...

  10. 【干货】Linux内存数据的获取与转存 直捣密码

    知识源:Unit 2: Linux/Unix Acquisition 2.1 Linux/Unix Acquistion Memory Acquisition 中的实验demo部分  小白注意,这是网 ...