P5644 [PKUWC2018]猎人杀

2023-05-16

P5644 [PKUWC2018]猎人杀

题目大意

一开始有 n n n个猎人,第 i i i个猎人有仇恨度 w i w_i wi。每次可以开枪射杀一个活着的猎人。

假设活着的猎人为 i 1 , i 2 , … , i m i_1,i_2,\dots,i_m i1,i2,,im,则第 i k i_k ik个猎人被射杀的概率是 w i k ∑ j = 1 m w i j \frac{w_{i_k}}{\sum\limits_{j=1}^mw_{i_j}} j=1mwijwik

1 1 1号猎人最后一个被射杀的概率。输出答案对 998244353 998244353 998244353取模。

w i > 0 , 1 ≤ ∑ w i ≤ 1 0 5 w_i>0,1\leq \sum w_i\leq 10^5 wi>0,1wi105


题解

转化题意

在不断射杀的过程中,概率的分母会不断改变。所以,我们可以稍微转化一下题意。

s u m = ∑ i = 1 n w i sum=\sum\limits_{i=1}^nw_i sum=i=1nwi,题意转化为:第 i i i个人被射杀的概率为 w i s u m \dfrac{w_i}{sum} sumwi,已经被射杀的人仍能继续被射杀。如果打中一个活着的人,那么这个人就死去。

为什么呢?因为在每次射杀的时候,每个活人被射杀的概率都他的仇恨度除以所有活人仇恨度的和。这样相对于原来,多了一个射杀死人的过程,但因为活人最终总会被射杀,所以本质上是一样的。

容斥

直接求 1 1 1号最后被射杀的概率比较困难,我们考虑使用容斥。

设在 1 1 1号之后被射杀的人的子集为 S S S的概率为 p ( S ) p(S) p(S),则答案为

a n s = ∑ ( − 1 ) ∣ S ∣ p ( S ) ans=\sum(-1)^{|S|}p(S) ans=(1)Sp(S)

然后,我们考虑如何求 p ( S ) p(S) p(S)

v ( S ) = ∑ i ∈ S w i v(S)=\sum\limits_{i\in S}w_i v(S)=iSwi。因为在 1 1 1号之后被射杀的人包含 S S S,所以就相当于射杀若干次,每次射杀除了 1 1 1号和集合 S S S之外的人,直到打中 1 1 1号。

p ( S ) = ∑ i = 0 + ∞ ( s u m − w 1 − v ( S ) s u m ) i ⋅ w 1 s u m p(S)=\sum\limits_{i=0}^{+\infty}(\dfrac{sum-w_1-v(S)}{sum})^i\cdot\dfrac{w_1}{sum} p(S)=i=0+(sumsumw1v(S))isumw1

接下来求 ∑ i = 0 + ∞ ( s u m − w 1 − v ( S ) s u m ) i \sum\limits_{i=0}^{+\infty}(\frac{sum-w_1-v(S)}{sum})^i i=0+(sumsumw1v(S))i。因为 s u m − w 1 − v ( S ) s u m \frac{sum-w_1-v(S)}{sum} sumsumw1v(S) [ 0 , 1 ) [0,1) [0,1)上,所以其无限次方为 0 0 0。由等比数列求和公式可得

∑ i = 0 + ∞ ( s u m − w 1 − v ( S ) s u m ) i = 1 − ( s u m − w 1 − v ( S ) s u m ) + ∞ 1 − s u m − w 1 − v ( S ) s u m = 1 w 1 + v ( S ) s u m = s u m w 1 + v ( S ) \sum\limits_{i=0}^{+\infty}(\frac{sum-w_1-v(S)}{sum})^i=\dfrac{1-(\frac{sum-w_1-v(S)}{sum})^{+\infty}}{1-\frac{sum-w_1-v(S)}{sum}}=\dfrac{1}{\frac{w_1+v(S)}{sum}}=\dfrac{sum}{w_1+v(S)} i=0+(sumsumw1v(S))i=1sumsumw1v(S)1(sumsumw1v(S))+=sumw1+v(S)1=w1+v(S)sum

所以

p ( S ) = s u m w 1 + v ( S ) ⋅ w 1 s u m = w 1 w 1 + v ( S ) p(S)=\dfrac{sum}{w_1+v(S)}\cdot \dfrac{w_1}{sum}=\dfrac{w_1}{w_1+v(S)} p(S)=w1+v(S)sumsumw1=w1+v(S)w1

那么

a n s = ∑ ( − 1 ) ∣ S ∣ w 1 w 1 + v ( S ) ans=\sum(-1)^{|S|}\dfrac{w_1}{w_1+v(S)} ans=(1)Sw1+v(S)w1

生成函数

依题意, ∑ w i ≤ 1 0 5 \sum w_i\leq 10^5 wi105,所以我们可以枚举 v ( S ) v(S) v(S)

g ( i ) = ∑ v ( S ) = i ( − 1 ) ∣ S ∣ g(i)=\sum\limits_{v(S)=i}(-1)^{|S|} g(i)=v(S)=i(1)S

那么

a n s = ∑ i = 0 s u m g ( i ) ⋅ w 1 w 1 + v ( S ) ans=\sum\limits_{i=0}^{sum}g(i)\cdot\dfrac{w_1}{w_1+v(S)} ans=i=0sumg(i)w1+v(S)w1

那问题就转化为求 g ( i ) g(i) g(i)了。用生成函数, g ( i ) g(i) g(i)其实就是 ∏ i = 2 n ( 1 − x w i ) \prod\limits_{i=2}^n(1-x^{w_i}) i=2n(1xwi)的第 i i i次项的系数。

N T T NTT NTT

接下来,我们要用 N T T NTT NTT来求 ∏ i = 2 n ( 1 − x w i ) \prod\limits_{i=2}^n(1-x^{w_i}) i=2n(1xwi)

用分治,求 [ l , r ] [l,r] [l,r]的多项式时,先求出 [ l , m i d ] [l,mid] [l,mid] [ m i d + 1 , r ] [mid+1,r] [mid+1,r]的多项式,在将两个多项式相乘,即可求出。

我们把求的过程看作 log ⁡ n \log n logn层,每层的时间复杂度为 O ( s u m log ⁡ s u m ) O(sum\log sum) O(sumlogsum),所以总时间复杂度为 O ( s u m log ⁡ s u m log ⁡ n ) O(sum\log sum\log n) O(sumlogsumlogn)

总时间复杂度可以看作 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

code

#include<bits/stdc++.h>
using namespace std;
long long ans=0,w[100005],f[500005],g[20][500005];
const long long G=3,mod=998244353;
long long mi(long long t,long long v){
	if(!v) return 1;
	long long re=mi(t,v/2);
	re=re*re%mod;
	if(v&1) re=re*t%mod;
	return re;
}
void ch(long long *a1,int l){
	for(int i=1,j=l/2;i<l-1;i++){
		if(i<j) swap(a1[i],a1[j]);
		int k=l/2;
		while(j>=k){
			j-=k;k>>=1;
		}
		j+=k;
	}
}
void ntt(long long *a1,int l,int fl){
	long long W,wn;
	for(int i=2;i<=l;i<<=1){
		if(fl==1) wn=mi(G,(mod-1)/i);
		else wn=mi(G,mod-1-(mod-1)/i);
		for(int j=0;j<l;j+=i){
			W=1;
			for(int k=j;k<j+i/2;k++,W=W*wn%mod){
				long long t=a1[k],u=W*a1[k+i/2]%mod;
				a1[k]=(t+u)%mod;
				a1[k+i/2]=(t-u+mod)%mod;
			}
		}
	}
	if(fl==-1){
		long long ny=mi(l,mod-2);
		for(int i=0;i<l;i++) a1[i]=a1[i]*ny%mod;
	}
}
int solve(int l,int r,long long *a1,int now){
	if(l==r){
		a1[0]=1;a1[w[l]]=mod-1;
		return w[l];
	}
	int mid=l+r>>1,vt,len=1;
	vt=solve(l,mid,a1,now+1)+solve(mid+1,r,g[now+1],now+1);
	while(len<=vt) len<<=1;
	ch(a1,len);ch(g[now+1],len);
	ntt(a1,len,1);ntt(g[now+1],len,1);
	for(int i=0;i<len;i++){
		a1[i]=a1[i]*g[now+1][i]%mod;
		g[now+1][i]=0;
	}
	ch(a1,len);
	ntt(a1,len,-1);
	return vt;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&w[i]);
	}
	if(n==1){
		printf("1");return 0;
	}
	int vt=solve(2,n,f,0);
	for(int i=0;i<=vt;i++){
		ans=(ans+f[i]*w[1]%mod*mi(w[1]+i,mod-2)%mod)%mod;
	}
	printf("%lld",ans);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

P5644 [PKUWC2018]猎人杀 的相关文章

随机推荐

  • 小觅双目摄像头标准版系列产品参数比较

  • java for无限循环

    for无限循环的几个情况 判断条件为true 会无限循环 省略了判断条件 会无限循环 判断条件为true 会无限循环 package test010 public class Main nbsp nbsp nbsp public stati
  • 计数器与定时器有何区别

    计数器是当你开始从0开始计数时一直不停的开始记数 除非你让他停下来要不他会不停的记下去 而定时器则是不一样的 是需要你自己先设定一个时间然后开始倒计时 当你的所定时间倒计完以后 他就自动停止下来了 懂了吗 至于用哪个就要看你干什么而定了 8
  • C++基础知识

    1 面向对象的程序设计思想是什么 xff1f 答 xff1a 把数据结构和对数据结构进行操作的方法封装形成一个个的对象 2 什么是类 xff1f 答 xff1a 把一些 具有共性的对象归类后形成一个集合 xff0c 也就是所谓的类 3 对象
  • 【开关电源】降压变换器(BUCK)的断续模式建模

    1 前言 在DCDC变换器中BUCK变换器是最基础的一类降压型变换器 xff0c 它可以将输入电压降低后输出 在连续模式CCM下 xff0c 输出和输入之间的比值是D xff08 D为占空比 xff09 这种开关变换器是一种通过电子开关周期
  • 变量命名规范

    本文转载于https blog csdn net ZCF1002797280 article details 51495229 是我见过的描述最精炼 最好懂的命名文档 xff0c 故收藏转载推荐 1 驼峰命名法 1 1 小驼峰法 除第一个单
  • C++实现websocket服务器握手协议(使用Qt)

    前提 xff1a 笔者在开发server程序时 xff0c 要求websocket与server连接 websocket的机制是在第一次连接时进行握手协议 xff0c 协议通过 xff0c 才可以进行正常的通信 xff0c 否则websoc
  • 00011__ARM和STM32的区别

    https blog csdn net qq 34385566 article details 79668280
  • linux中查看系统资源占用情况的命令

    size 61 large top size 主要参数 d xff1a 指定更新的间隔 xff0c 以秒计算 q xff1a 没有任何延迟的更新 如果使用者有超级用户 xff0c 则top命令将会以最高的优先序执行 c xff1a 显示进程
  • 关于PendSV异常和SVC异常

    这里先说什么是异常 xff0c 什么是中断 xff1f 请下这张图 颜色加深的表项为异常 xff0c 这些属于cm3内核自带的 其中 3 xff0c 2 xff0c 1异常的优先级固定 xff0c 是不可更改的 xff0c 其余的异常中断优
  • FreeRTOS学习4-任务创建和删除

    关于任务创建有3个函数 1 动态创建一个任务 可以自动分配任务堆栈和TCB FreeRTOSConfig h中 xff0c 需要定义 define configSUPPORT DYNAMIC ALLOCATION 1 支持动态内存申请 Ba
  • java里 equals和== 区别

    1 java中equals和 61 61 的区别 值类型是存储在内存中的堆栈 xff08 简称栈 xff09 xff0c 而引用类型的变量在栈中仅仅是存储引用类型变量的地址 xff0c 而其本身则存储在堆中 2 61 61 操作比较的是两个
  • VRPTW建模与求解—基于粒子群算法

    VRPTW建模与求解 基于粒子群算法 1 VRPTW简要描述 VRPTW xff08 Vehicle Routing Problem with Time Windows xff09 是指在经典VRP的前提上 xff0c 给每个客户增添时间窗
  • 伽马分布,指数分布,泊松分布的关系 -转自简书

    原文链接 xff1a https www jianshu com p 6ee90ba47b4a 伽马分布 xff0c 指数分布 xff0c 泊松分布的关系 thinkando 关注 2018 09 25 21 13 字数 714 阅读 29
  • 双轴驱动步进电机云台二自由度单片机控制程序PTU57

    高精度云台由两个电机驱动 xff0c 可控制方位角和高度角 xff0c 具有两自由度的机械电子设备 可用于机器视觉 摄影摄像 监控安防 天文观测 雷达扫描 DIY雕刻机 转盘转台 智能机械手臂 双轴跟踪太阳能定日镜等各类应用高精度云台的场合
  • php使用curl获取需要认证的https请求

    lt php php使用curl获取需要认证的https请求的方法 url 61 34 XXXXXX 34 arr header 61 34 Accept application json 34 arr header 61 34 Autho
  • i-vector本质剖析

    1 i vector的由来 基于因子分析理论 xff0c 句子h的超向量可以描述成 其中为ubm模型的均值超向量 xff0c 即为i vector 2 i vector的计算 2 1 T矩阵的估计 为句子h的观察特征 xff0c 可以对应于
  • C++程序设计基础实验-实验七 多态性

    实验七多态性 一 实验目的 掌握运算符重载的方法 xff1b 掌握使用虚函数的继承实现动态多态性 掌握纯虚函数及抽象类的使用 二 实验内容 设计复数类Complex xff08 请参照教材例题8 1的设计 xff09 xff0c 实现运算符
  • g2o_a_general_framework_for_graph_optimaization

    g2o A General Framework for Graph Optimization NONLINEAR GRAPH OPTIMIZATION USING LEAST SQUARES 机器人和计算机视觉中的许多问题都可以用下列方程的
  • P5644 [PKUWC2018]猎人杀

    P5644 PKUWC2018 猎人杀 题目大意 一开始有 n n n 个猎人 xff0c 第 i i i 个猎人有仇恨度