【比赛】【SMOJ 2019.5.26】

\(\mathrm{T1}\)

我们看一下题目中的式子:

\(a\times c=b\times d\)

难道就没有想到什么吗?

如果\(\dfrac{a}{b}=\dfrac{c}{d}\),则\(ad=bc\)

这……不就是十字相乘法嘛。

也就是:

\(a\times c=b\times d \\ \dfrac{a}{b}=\dfrac{d}{c}\)

我们就可以维护一个\(\mathrm{key}\)是数组当中两个元素之间的比的std::map即可。

只不过在统计答案的时候要反过来统计(因为\(d\to c\)\(a\to b\)的大小顺序是反的)

\(\mathrm{Code}\)


\(\mathrm{T3}\)

首先考虑两个儿子的贡献

可以发现,如果不确定的儿子的值越大,排列的限制就越多
(比如说,如果上面那幅图取\(3\),排列组合就没有限制,两个儿子分别把根节点两边剩下的位置全排列就是贡献)
(但如果取的值是\(5\),那么\(5\)那一边的排列就不能包含\(3\)\(4\)

而且那个不确定的儿子本身的取值也有限制
比如,如果根节点在第\(4\)个位置,确定的儿子(就是\(2\))在根节点的左边,那么不确定的儿子最大就只能取到4的下一个数字(也就是\(5\)),不然就一定不合法。

也就是说,假如我取\(3\),没有限制,那么我对应的排列数就是\(\mathrm{P}(len-3,len-pos-1)\),代表从根节点和左右两个儿子之外(减去\(3\)之后),把 根节点右边 除了右儿子以外的所有位置 都全排列一次

然后取值每增加1,能够放到右边的数的个数就减少\(1\)
(比如选\(4\),那么\(3\)就不能放;选\(5\),那么\(3\)\(4\)都不能放,这样一直减下去,最后到达循环边界时,排列的两个自变量刚好相等,表示右边的数一个都不能到左边去,只能在右边一个个全排列)

右边弄清楚之后,左儿子因为是2,所以无论取其他什么值都肯定比2大,所以直接把左边剩下的位置全排列(\(\mathrm{P}(pos-2,pos-2)\))即可


然后再考虑子树的贡献

现在就不是排列而是组合了(因为DP状态里面没有规定大小顺序)
然后还是跟上面类似,一开始num取3,后面num每增加1,组合的第一维就减1,表示能够选的数少了

然后,左子树的贡献要乘右子树的排列(因为右边每一种排列情况左子树都有贡献),同理,右子树的贡献要乘左子树的排列

把那些随着num变化的P和C取个前缀和,省略掉枚举num的那个循环就是std。

\(\mathrm{Code}\)

posted @ 2019-08-21 17:44  info___tion  阅读(114)  评论(0)    收藏  举报