[HNOI2015]开店
建出点分树,每个点管辖它的子树。
设(f[x])表示(x)到子树的距离和。
点分树的性质:一个点到另一个点的路径一定经过点分树的(lca)。
在每次查询的时候,从一个点跳父亲,假设跳到(y)。
为了避免算重,查询(y)的不包含(x)的儿子。
由于节点的度数都不超过(3),暴力扫描这个点的所有儿子即可。
查询(y)的时候要计算(x~y)距离*(y)不包含(x)的大小+(y)的不包含x的儿子到(y)的距离。
现在考虑有年龄限制的情况,显然把每个表排序后二分即可。
[HNOI2015]接水果
显然的整体二分。
考虑如何判断。每次二分一个值(md),把(<=md)的路径插入,再判定当前点的(k)是否<=包含它的路径个数。
多组询问使用整体二分。每次插入所有(<=md)的路径,再判定每个询问点的(k)是否<=包含它的路径个数,以判定接下来要缩的区间。
判定可以使用线段树+扫描线。对树dfs序,若(in_{x})表示(x)子树的最小dfs序,(ou_{x})表示(x)子树的最大dfs序。
则把一条路径投射到平面形成一个点((in_x,in_y))。
对于每条路径,如果一个点x是另一个点y的祖先,则求出x->y的第一个点z,
形成矩形([1,in_z][in_b,ou_b])和([in_b,ou_b+1][ou_z+1,n])
否则在平面上形成了矩形([in_a,ou_a][in_b,ou_b])。
把所有矩形在平面上+1,查询每个点的权值,得到了这个点被覆盖的次数。
思路较简单,但是代码很难写。
[HNOI2015]亚瑟王
题目中每张卡发动技能的贡献都是独立的,所以可以分开算。
题目发动技能的规则比较恶心,但是实际上一张卡发动技能的概率只和前面的卡发动技能的概率相关。
设(f_{i,j})表示在所有的(r)轮中,前(i)张卡出了(j)张的概率。
(f_{i,j})可以从(f_{i-1,j})或者(f_{i-1,j-1})转移,表示当前点是否发动技能。
在统计答案的时候,求出每张卡被发动的概率(v_i)
枚举卡发动的轮(j)则(v_i+=f_{i-1,j}*(1-(1-p_i)^{r-j}))
最终把(v)和(d)对应位置乘起来得到答案。
[HNOI2015]实验比较
其实这题也是个套路。
先把所有被等号连接的变量缩成一个点。
题目中说明了(M<=n),所以如果把一个点向强制比它大的点连边则形成了基环内向森林。
其中,有环的连通块一定无解,可以使用拓扑排序判定。
判完无解后,使用一个超级源点(s)向所有树根连边。这样子答案不变,因为超级源点的值肯定是(<=)其他点的。
根据套路设(f_x)表示x点的答案。但是在合并两棵子树时,小于号和等于号十分麻烦。
注意到子树的方案一定是有若干个小于号和等于号连接的。
所以设(f_{x,i})表示(x)的子树中有(i)个段,每个段使用等号连接,不同的段之间用不等式连接。且第一个段中要包含(x)。
考虑合并两棵树(x,y),假设(x)有(i)个段,(y)有(j)个段,合并到的新树(x')有(k)个段。
(x')中的每一段可以是(x)(y)的某一段,也能是(x,y)的两段。
但是不能来自同一棵子树,因为在子树中大小关系已经确定。
则系数是(C_{i-1}^{j-1}*{C_{j-1}^{k-i+j}})。
原因是枚举(y)中的(j-1)段在(x')放的位置,再把(x)的(i-j)段放在剩下的位置,使得每一段都不为空。
(x')中还剩下(k-i+j)段,考虑和(y)中的段合并。
由于根必须在第一段,所以转移系数的上面下面部分都要-1。
[HNOI2015]落忆枫音
为什么我想到了容斥想到了计算公式却做不出来。。。。
题目要求我们加一条边后求出从1号点开始的有向树。
如果加的边的出点是1,则这条边是无效的。
只需要考虑加的边的出点不是1的情况。
加了边后,图中可能有若干个环,可以容斥,算出一定要包含环的树的个数再用答案减去。
先考虑总方案怎么计算。如果不考虑是否合法,则一个点可以选出恰好一个前驱,答案就是所有点(v)的(deg_{v})的乘积。
加了边考虑如何计算答案。设加了边后的度数数组为(deg'),(deg')的每一个元素的乘积为(ans)。则(ans)再除以环上的边就是要包含环的有向树的个数。
可以(dp)计算。设(f_{i})表示(t)点->(i)点的边的(deg)值的逆元之和,最后乘上ans就是要扣去答案。
则先(f_i*=frac{1}{deg'_i})再(f_{v}+=f_{i}),其中(v)和(i)在未加边的原图中有边,表示累积路径的权值。并且计算(deg)的乘积。
[HNOI2015]菜肴制作
发现如果要让标号小的点尽量靠前,则它的前驱选完后紧接着就选这个点。
假设现在选的点是(x),(x)和它的后继肯定占用了答案序列的一段前缀。把这个前缀从答案序列和图中删除,继续执行这个过程直到只有1个点。则未被删除的最后一个点肯定是目前权值最大且没有出度的点。这个点肯定在答案序列的末尾,把这个点删除,继续执行这个过程,且把每个得到的点依次插入在答案序列的开头,直到原图为空。
实际上这个过程就是用在反图上用堆进行的拓扑排序。