持续更新ing……
玩具谜题
模拟,随便搞
天天爱跑步
注意到每一条路径可以拆成两条从祖先到子孙的不拐弯的链,分别为s->lca和lca->t,于是考虑差分标记,分开做。那么只需要考虑两个问题:值如何维护?标记如何合并?
第一种情况,即从s->lca的链,记跑到一个点的时刻为 timei 。直接维护它不容易,但可以发现 timei−depi 为定值,于是我们可以将 timei 转化为 timei−depi 来做,随着 depi 的变化可以轻松计算出 timei ,第一个问题解决。再考虑值的合并,强行合并每次是 O(n) 的,有一个合并相同区间内出现次数的好办法,建出权值线段树,然后合并线段树。合并完所有元素是 O(nlogn) 的(证明见下[1]),第二个问题解决。第一种情况解决。
对于第二种情况,同理可将 timei 转化为 timei+depi 来做,标记合并方法相同。第二种情况也解决。
总时间复杂度 O(nlogn)
总结:考场上考虑出了拆成两条链来做和 timei 和 depi 的转化,然而我不会线段树合并,然后就惨了。
[1]线段树合并复杂度 O(nlogn) 证明:插入一个元素会影响logn个节点,一共有n个元素,所以一共会影响nlogn个结点。每一次合并两个线段树的同一个结点,会将两个被影响的结点变为一个被影响的结点,相当于减少了一个被影响的节点。由于只有nlogn个被影响的结点,故最多只能合并nlogn次,即时间复杂度 O(nlogn) 。
换教室
考场上被第二题困扰,没去想这题,可惜。
记f[i][j][0/1][0/1]表示做到第i次,已经申请j次,这一次是否申请,如果申请是否成功的代价。但这样是错的,因为这样会使得这一次申请成功与否的代价和上一次是否申请的代价之间产生联系。就变成根据上一次的决策来决定这一次选不选了,即申请成功可能由上一次不申请转移,而申请不成功可能由上一次申请转移。
要记f[i][j][0/1]表示做到第i次,已经申请j次,这一次是否申请的代价。第三维为0意味着这一次一定在c[i]位置,那么可以从前一次的0或1转移过来,如果从1转移过来,前一次有两种不同的概率分别会在c[i-1]或d[i-1],要分2类。另一种,第三维为1意味着这一次有概率分别会在c[i]或d[i]位置,同样可以从前一次转移,注意要分4类了。这样每一次申请或者不申请的代价只和前一次申请或者不申请的代价有关,而不会被拆成成功与否而使得成功与失败的代价转移不同。
总结:最优期望问题所设计的DP方程一般是根据决策者所能知道的信息来设计的,并用它来算出最大(最小)期望(概率)。
组合数问题
前缀和,随便搞
蚯蚓
容易想到一个暴力算法,直接用堆维护最大值,外面设一个变量来统计没被切掉的蚯蚓长度的增加值。入堆时元素减去这个值就可以维护了。复杂度是 O(mlogm) 的,无法接受。
注意到一个性质,每一次切的蚯蚓的长度必然是单调不增的,这意味着每一次看下来的两段也是单调不增的。既然不增,就没必要用堆,用队即可维护。建两三个队分别维护初始蚯蚓序列,切掉后较长的一段,切掉后较短的一段。每次取max即可, O(m) 。