【比赛】【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{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。

浙公网安备 33010602011771号