问题的引出
leetcode上的1223题:投掷一个骰子n次,并给出一个长度为6的数组,数值不超过15,分别表示1,2,3,4,5,6不能连续出现的次数,求投这n次可能出现的满足要求的序列的种数。用一个三维数组 a [ 6 ] [ 16 ] [ n ] a[6][16][n] a[6][16][n]进行动态规划就可以解决。但是现在加强一下限制,去掉限制中连续出现的条件,即数组每个数分别表示1,2,3,4,5,6在序列中能够出现的最大次数。可以用一个二维数组 a [ 6 ] [ n ] a[6][n] a[6][n]来进行动归, a [ i ] [ j ] a[i][j] a[i][j]表示投掷 j j j次只出现前 i i i个数的情况数。动归方程为 a [ i ] [ j ] = ∑ k = 0 m i n ( r [ i ] , j ) C j k a [ i − 1 ] [ j − k ] a[i][j]=\sum_{k=0}^{min(r[i],j)}C_j^ka[i-1][j-k] a[i][j]=∑k=0min(r[i],j)Cjka[i−1][j−k],其中 r [ i ] r[i] r[i]表示数字 i i i能出现的最大次数。发现递归式子中有组合数,只要n稍微大一些,就会出现组合数超过int表示范围的情况,因此题目要求输出模 1 0 9 + 7 10^9+7 109+7的结果。因此这里就涉及到求组合数的除以一个质数的余数的问题,如果是排列数,那很简单,因为只有乘法,现在麻烦的是组合数里面有除法,不能使用简单的同余公式来求。
问题的解决
我在网上查找带除法的同余问题,发现可以通过求分母的逆元来解决,求逆元的方法具体参考这里。比如要求 a / b a/b a/b除以质数 c c c的余数,由于质数的同余构成一个群,我们可以求出 b b b的逆元 b ′ b' b′,这样就只需要求 a ∗ b ′ a*b' a∗b′除以 c c c的余数了。