[BZOJ2313]分组
把问题拆成两问:
- 求出当m=1的时候的方案数ans
- 计算m^ans mod (10^9-401)
先考虑第二问。
显然第一问的ans很大很大,而答案只是要 mod (109-401)的值,而109-401刚好是一个质数。由费马小定理知,a^n mod p == a^(n mod (p-1)) mod p。因此我们要求出ans mod (p-1),之后快速幂处理就好了。麻烦的就是如何求出ans mod (p-1)。
接下来考虑第一问。
考虑每一个盒子放i个球,那么就总共需要n/i个盒子,这种情况下的方案数就是:C(n, i) * C(n-i, i) * C(n-2i, i) * ... * C(i, i) / P(n/i, n/i)根据排列组合的定义,可以化简为:
n! / (i!^(n/i) * (n/i)!)
这就是ans的精确值。
现在我们要求的是ans mod (10^9-401-1)的值,就必须用中国剩余定理进行拆分了。x ≡ count[0] (mod A[0]) x ≡ count[1] (mod A[1]) x ≡ count[2] (mod A[2]) x ≡ count[3] (mod A[3])
其中count[i]是ans mod A[i]的值,A[] = {2, 13, 5281, 7283}。问题变成求满足上述同余方程组的x,得到count[]后用中国剩余定理处理(见主程序的中国剩余定理部分)。
棘手的是如何求出ans%A[i]
观察ans,我们把问题转成求x/y mod p(p为A[]中的某个质数)。 不妨令x = a * p^b y = c * p^d
那么x/y mod p就要看b和d的关系了。由计算ans的公式可以发现,b >= d。 当b > d时,显然ans ≡ 0 (mod p) 当b == d时,ans ≡ a/c (mod p)。计算模上的除法一般转成乘上其乘法逆元,因此扩展欧几里德解之(见程序AdBModp)。
如何将n!转成a*p^b形式
注意到n! mod p = 1 * 2 * ... * (p-1) * p * (p+1) * (p+2) * ... * (2p-1) * 2p * ... * (kp+1) * (kp+2) * ... * (kp+m) mod p k就是[n/p] m就是n-kp = 1 * 2 * ... * (p-1) * p * 1 * 2 * ... * (p-1) * 2p * ... * 1 * 2 * ... * m mod p = [(n%p)! * (p-1)!^(n/p)] * [(n/p)! * p^(n/p)] mod p
假设n! = a * p^b 初始a = 1, b = 0 因为(n-n/p)! mod p、(p-1)!(n/p) mod p很小,可以预处理算出,为x。 那么a = ax, b = b+(n/p)。 然后递归处理(n/p)!最后就得到了n! = a * p^b
end
好了,基本所有的都讲完了,我觉得讲的有点像递归……为了得到那个同余方程组费了好大劲 ……到最后还要记得用中国剩余定理求解(具体在程序中有注释)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
|