PKUWC2018题解

PKUWC2018题解

Minimax

显然最终权值只能是所有叶子中的权值,设(f_{i,j})表示以(i)节点的数字为(j)的概率,这个dp很简单。
这时候暴力向上合并是(O(n^2))的,想办法优化向上合并的效率。

考虑线段树合并,如果只有一个儿子直接继承就行了,关键是两个儿子也就是两颗线段树怎么合并。

对于两颗待合并的线段树,我们设一个函数(merge(x,y,sx,sy,v))表示当前合并的根节点分别为(x,y),其中(sx)表示(y)(x)贡献为(sx)(sy)表示(x)(y)贡献为(sy)(v)表示我们在原树上根节点所对应的概率。

那么当(x)(y)为空时,可以直接对非空的根打上一个所对应贡献的标记。

因为事实上这棵值域线段树中是对应了一段区间的,而往下递归时每棵树的权值大小关系确定我们将一段区间对于另外一段区间的贡献直接作用在(sx,sy)上,向下递归即可。

实现细节详见代码。

代码

Slay the Spire

令强化牌为({a}),攻击牌为({b}),将(a,b)按照从大到小排序。

(f_{i,j})表示强化牌选到且选第(i)张,选了(j)张牌方案数的乘积和
(g_{i,j})表示攻击牌选到且选第(i)张,选了(j)张牌方案数的和的和
那么有转移

[egin{cases} f_{i,j}=sum_{k=0}^{i-1}f_{k,j-1} imes a_i\ g_{i,j}=sum_{k=0}^{i-1}g_{k,j-1}+ {k-1choose j-2} imes a_i end{cases} ]

前缀和优化可做到(O(n^2))
(mathbf F(i,j))表示抽到强化牌(i)张牌,打了(j)张的方案数的贡献乘积和
(mathbf G(i,j))表示抽到攻击牌(i)张牌,打了(j)张的方案数的贡献和的和
那么因为你肯定只会选最大的几张,

[egin{cases} mathbf F(i,j)=sum_{k=j}^n f_{k,j} imes{n-kchoose i-j}\ mathbf G(i,j)=sum_{k=j}^n g_{k,j} imes{n-kchoose i-j} end{cases} ]

又因为(a,b)均单调不增且(forall a_i>1),所以在保证至少一次攻击的情况下尽可能多选强化牌。

枚举抽了(i)张强化牌,那么每次的贡献为

[egin{aligned} egin{cases} mathbf F(i,i) imesmathbf G(m-i,k-i)&i<k\ mathbf F(i,k-1) imes mathbf G(m-i-1,1)& ext{otherwise} end{cases} end{aligned} ]

然后做完了,总复杂度(O(n^2))

代码

斗地主

我怎么可能会做这种题啊

随机算法

有一个直观的想法就是设(f_{i,S})表示目前所选排列中按顺序填了(i)个数,所有数的状态为(S)的方案数,其中(S)为一个三进制状态,(0,1,2)分别表示没选/选了且在独立集中/选了但不在独立集中的方案数。

你发现其实(2)状态是没必要的,因为每个与当前独立集冲突的数对于答案的贡献相同,记目前与可放入独立集的个数为(cnt),这一部分可以直接转移,另外一部分不能直接转移的对下一个状态(f_{i+1,S})的贡献和就是(f_{i,S} imes (n-i-cnt)),细节详见代码。

代码

猎人杀

考虑你打死一个人不是把他毙了,而是打上一个标记,如果这一次打到他就再换一个人打。
考虑容斥,就是说目前有一个集合(S)(1)后面被打,令(W=sum_{iin S} w_i,A=sum_{i=1}^n w_i)那么答案就是

[egin{aligned} Ans&=sum_S(-1)^{|S|}sum_{i=0}^{infty}(1-frac{W+w_i}{A})^ifrac{w_i}{A}\ &=sum_S(-1)^{|S|}frac {w_1}{W+w_1} end{aligned} ]

用分治(+NTT)把所有(frac 1W)的系数背包出来最后算一下答案即可。

代码

随机游走

"至少"比较难求,考虑(min-max)容斥的式子:

[max E(S)=sum _{Tsubseteq S} (-1)^{|T|+1}min E(T) ]

那么一个集合(S)(min)就是第一次到达(S)中一个点的期望时间。

(f_{i,S})表示从(i)出发走到(S)的一个点的时间的期望,那么有

[egin{aligned} egin{cases} f_{i,S}=0&(iin S)\ f_{i,S}=1+frac {sum_{(i,j)} f_{j,S}}{deg_i} &(i otin S) end{cases} end{aligned} ]

把下面的转移拆一下:

[egin{aligned} f_{i,S}&=1+frac {sum_{(i,j)} f_{j,S}}{deg_i}\ &=1+frac {f_{fa_i, S}}{deg_i}+frac {sum_{jin son_i}f_{j, S}}{deg_i} end{aligned} ]

因为图是一棵树且叶子节点的值只与其父亲有关,那么所有(f_{i,S})能表示为(A_if_{fa_i,S}+B_i)的形式。
代到上面的式子里:

[egin{aligned} f_{i,S}&=1+frac {f_{fa_i, S}}{deg_i}+frac {sum_{jin son_i}A_jf_{i, S}+B_j}{deg_i}\ &=frac{f_{fa_i, S}}{deg_i-sum_{jin son_i}A_j}+frac{sum_{jin son_i}B_j+deg_i}{deg_i-sum_{jin son_i}A_j} end{aligned} ]

发现(A_i=frac{1}{deg_i-sum_{jin son_i}A_j},B_i=frac{sum_{jin son_i}B_j+deg_i}{deg_i-sum_{jin son_i}A_j})

然后根节点的(f_{rt,S})就是(B_{rt}),这样的话把所有(f)求出来高维前缀和即可。

代码

原文地址:https://www.cnblogs.com/heyujun/p/11985727.html