题目链接:
题目描述:
就是有n个苹果,要选出来m个,问有多少种选法?还有k个素数,p1,p2,p3,...pk,结果对lcm(p1,p2,p3.....,pk)取余。
解题思路:
Lucas + 中国剩余定理,注意的是中国剩余定理的时候有可能会爆long long。然后用一个快速加法就好辣。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 typedef __int64 LL; 8 const int maxn = 20; 9 10 LL quick_mul (LL a, LL b, LL mod) 11 { 12 LL res = 1; 13 while (b) 14 { 15 if (b % 2) 16 res = (res * a) % mod; 17 a = (a * a) % mod; 18 b /= 2; 19 } 20 return res; 21 } 22 23 LL quick_add (LL a, LL b, LL mod) 24 { 25 LL res = 0; 26 while (b) 27 { 28 if (b % 2) 29 res =(res + a) % mod; 30 a = (a + a) % mod; 31 b /= 2; 32 } 33 return res; 34 } 35 36 LL C (LL n, LL m, LL mod) 37 { 38 if (n < m) 39 return 0; 40 LL ans = 1; 41 for (int i=1; i<=m; i++) 42 { 43 LL a = (n - m + i) % mod; 44 LL b = i % mod; 45 ans = ans * (a * quick_mul(b, mod - 2, mod) % mod) % mod; 46 } 47 return ans; 48 } 49 50 LL Extended_Euclid (LL a, LL b, LL &x, LL &y) 51 {//a, b只能是正数 52 if (b == 0) 53 { 54 x = 1; 55 y = 0; 56 return a; 57 } 58 59 LL r = Extended_Euclid (b, a%b, x, y), t; 60 t = x; 61 x = y; 62 y = t - a / b * y; 63 return r; 64 } 65 66 LL CRT (LL a[], LL b[], LL n) 67 { 68 LL M = 1, ans = 0; 69 LL Mi, x, y; 70 71 for (int i=0; i<n; i++) 72 M *= a[i]; 73 74 for (int i=0; i<n; i++) 75 { 76 Mi = M / a[i]; 77 LL d = Extended_Euclid (Mi, a[i], x, y); 78 x = (x % a[i] + a[i]) % a[i]; 79 //注意,这里的x有可能是负数要注意取mod,变成正的 80 81 //或者quick_add 的第二个参数传Mi 82 LL res = quick_add (x, Mi, M); 83 res = quick_add (res, b[i], M); 84 ans = (ans + res) % M; 85 } 86 return (ans + M) % M; 87 } 88 LL Lucas (LL n, LL m, LL mod) 89 { 90 if (m == 0) 91 return 1; 92 return (C(n%mod, m%mod, mod) * Lucas(n/mod, m/mod, mod)%mod); 93 } 94 95 int main () 96 { 97 LL t, n, m, k, a[maxn], b[maxn]; 98 scanf ("%I64d", &t); 99 while (t --) 100 { 101 scanf ("%I64d %I64d %I64d", &n, &m, &k); 102 for (int i=0; i<k; i++) 103 { 104 scanf ("%I64d", &a[i]); 105 b[i] = Lucas (n, m, a[i]); 106 } 107 printf ("%I64d ", CRT (a, b, k)); 108 } 109 return 0; 110 }