【LOJ】#2541. 「PKUWC2018」猎人杀
题解
一道神仙的题><
我们毙掉一个人后总的w的和会减少,怎么看怎么像指数算法
然而,我们可以容斥……
设\(\sum_{i = 1}^{n} w_{i} = Sum\)
我们把问题转化一下,就是一个猎人死掉之后,并不认为他死掉了,他还活着,只是毙掉他的时候,再毙一次
很容易发现这是个正无穷的递归……但是……这是对的!
例如下一个毙掉\(i\)的概率,死掉的人的w和是\(B\),则
\(P = \frac{B}{A}P + \frac{w_{i}}{A}\)
我们当成一元一次方程解,很容易发现
\(P = \frac{w_{i}}{A - B}\)
很容易发现这个式子是对的
然后我们选出来一堆人,设这些人w的和为\(S\)
我们要求的是这些人在1号人以后毙掉的概率,剩下人随意
\(P = \sum_{i = 0}^{+\infty}(1 - \frac{S + w_{1}}{A})^{i} \frac{w_{1}}{A}\)
就是我们从除了第一个人和S这些人里找人毙掉,反正我们可以反复毙掉一个人,最后再乘上第一个人被毙掉的概率
这个式子可以写成这样
\(P = (1 - \frac{S + w_{1}}{A})P + \frac{w_{1}}{A}\)
解出来
\(P = \frac{w_{1}}{S + w_{1}}\)
……
好吧
然后我们显然容斥系数是(-1)的人数次幂,对于加入一个人,对系数的贡献是-1
我们可以用S进行分类,可以背包求出每个S的系数
然后发现这可以用生成函数进行优化\(\prod_{i = 2}^{n} (1 - x^{w_{i}})\)
很明显的分治NTT
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#define enter putchar('\n')
#define space putchar(' ')
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define pii pair<int,int>
#define eps 1e-7
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
typedef vector<int> poly;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 998244353,MAXL = 1 << 18;
int W[MAXL + 5],N,val[MAXN],sum;
poly ans;
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
void NTT(poly &f,int L,int on) {
f.resize(L);
for(int i = 1 ,j = L / 2 ; i < L - 1 ; ++i) {
if(i < j) swap(f[i],f[j]);
int k = L / 2;
while(j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
for(int h = 2 ; h <= L ; h <<= 1) {
int wn = W[(MAXL + on * MAXL / h) % MAXL];
for(int k = 0 ; k < L ; k += h) {
int w = 1;
for(int j = k ; j < k + h / 2 ; ++j) {
int u = f[j],t = mul(f[j + h / 2],w);
f[j] = inc(u,t);
f[j + h / 2] = inc(u,MOD - t);
w = mul(w,wn);
}
}
}
if(on == -1) {
int InvL = fpow(L,MOD - 2);
for(int i = 0 ; i < L ; ++i) f[i] = mul(f[i],InvL);
}
}
poly operator * (poly a,poly b) {
int t = a.size() + b.size();
int l = 1;
while(l <= t) l <<= 1;
NTT(a,l,1);NTT(b,l,1);
poly c;c.clear();c.resize(l);
for(int i = 0 ; i < l ; ++i) {
c[i] = mul(a[i],b[i]);
}
NTT(c,l,-1);
for(int i = l - 1 ; i >= 0 ; --i) {
if(c[i] == 0) c.pop_back();
else break;
}
return c;
}
void Init() {
srand(20020421);
W[0] = 1;W[1] = fpow(3,(MOD - 1) / MAXL);
for(int i = 2 ; i < MAXL ; ++i) W[i] = mul(W[i - 1],W[1]);
read(N);
for(int i = 1 ; i <= N ; ++i) {read(val[i]);sum += val[i];}
random_shuffle(val + 2,val + N + 1);
}
poly Solve(int l,int r) {
if(l == r) {
poly g;
g.clear();
g.resize(val[l] + 1);
g[val[l]] = MOD - 1;g[0] = 1;
return g;
}
int mid = (l + r) >> 1;
return Solve(l,mid) * Solve(mid + 1,r);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
if(N == 1) {
puts("1");
return 0;
}
ans = Solve(2,N);
int res = 0;
ans.resize(sum);
for(int i = 0 ; i <= sum ; ++i) {
res = inc(res,mul(ans[i],mul(val[1],fpow(val[1] + i,MOD - 2))));
}
out(res);enter;
return 0;
}
【LOJ】#2541. 「PKUWC2018」猎人杀的更多相关文章
- LOJ #2541「PKUWC2018」猎人杀
这样$ PKUWC$就只差一道斗地主了 假装补题补完了吧..... 这题还是挺巧妙的啊...... LOJ # 2541 题意 每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \fr ...
- LOJ 2541 「PKUWC2018」猎人杀——思路+概率+容斥+分治
题目:https://loj.ac/problem/2541 看了题解才会……有三点很巧妙. 1.分母如果变动,就很不好.所以考虑把操作改成 “已经选过的人仍然按 \( w_i \) 的概率被选,但是 ...
- loj#2541. 「PKUWC2018」猎人杀
传送门 思路太清奇了-- 考虑容斥,即枚举至少有哪几个是在\(1\)号之后被杀的.设\(A=\sum_{i=1}^nw_i\),\(S\)为那几个在\(1\)号之后被杀的人的\(w\)之和.关于杀了人 ...
- 「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 ...
随机推荐
- Hadoop部署方式-伪分布式(Pseudo-Distributed Mode)
Hadoop部署方式-伪分布式(Pseudo-Distributed Mode) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.下载相应的jdk和Hadoop安装包 JDK:h ...
- Java操作Kafka执行不成功的解决方法,Kafka Broker Advertised.Listeners属性的设置
创建Spring Boot项目继承Kafka,向Kafka发送消息始终不成功.具体项目配置如下: <?xml version="1.0" encoding="UTF ...
- codevs 2147 数星星
2147 数星星 http://codevs.cn/problem/2147/ 题目描述 Description 小明是一名天文爱好者,他喜欢晚上看星星.这天,他从淘宝上买下来了一个高级望远镜.他十分 ...
- puppeteer截图
puppeteer是谷歌官方出品的一个通过 DevTools 协议控制 headless Chrome 的Node库.可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进 ...
- SharePoint 项目的死法(二)
说实话, 做SharePoint项目或者任何信息化项目并不是个容易的事情, 但成功的IT项目对于一个企业来说也许意味着很多, 从我的观察来看, 大部分的成功的信息化项目给企业所带来的回报都远远超过其所 ...
- [转载]ECMA-262 6th Edition / Draft August 24, 2014 Draft ECMAScript Language Specification
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-23.4 Draft Report Errors and Issues at: htt ...
- Scala2.10.4在CentOS7中的安装与配置
随着基于内存的大数据计算框架——spark的火爆流行,用于编写spark内核的Scala语言也随之流行开来.由于其编写代码的简洁性,受到了越来越多程序员的喜爱.我今天给大家展示的时Scala2.10. ...
- Dynamic Rankings(动态第k大+树套树)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题目: 思路: 树套树板子题. 代码实现如下: #inclu ...
- oracle05
1. 数据处理 说完了所有的查询,下面说说增.删.改. 1.1. Update 在plsql Developer工具中,加上rowid可以更改数据. 使用工具进行更新数据的操作 在工具中更新数据方式一 ...
- IE安全系列之——RES Protocol
IE安全系列之--RES Protocol res Protocol用于从一个文件里面提取指定资源.语法为:res://sFile[/sType]/sID 各Token含义: sfile:百分号编码. ...