数学:拓展Lucas定理

拓展Lucas定理解决大组合数取模并且模数为任意数的情况

大概的思路是把模数用唯一分解定理拆开之后然后去做

然后要解决的一个子问题是求模质数的k次方

将分母部分转化成逆元再去做就好了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 100000 + 10;
 4 typedef long long LL;
 5 
 6 LL Pow(LL n, LL m, LL mod) {
 7     LL ans = 1;
 8     while(m > 0) {
 9         if(m & 1) ans = (LL)ans * n % mod;
10         n = (LL)n * n % mod; m >>= 1;
11     }
12     return ans;
13 }
14 LL Pow(LL n,LL m) {
15     LL ans = 1;
16     while(m > 0) {
17         if(m & 1) ans = ans * n;
18         n = n * n; m >>= 1;
19     }
20     return ans;
21 }
22 LL x, y;
23 LL exgcd(LL a, LL b) {
24     if(a == 0) {
25         x = 0, y = 1;
26         return b;
27     }LL r = exgcd(b%a, a);
28     LL t = x; x = y - (b/a)*x; y = t;
29     return r;
30 }
31 LL rev(LL a, LL b) { exgcd(a, b); return ((x % b) + b) % b; }
32 LL Calc(LL n, LL p, LL t) {
33     if(n == 0) return 1;
34 
35     LL s = Pow(p, t), k = n / s, tmp = 1;
36     for(LL i=1; i<=s; i++) if(i % p) tmp = (LL)tmp * i % s;
37 
38     LL ans = Pow(tmp, k, s);
39     for(LL i=s*k + 1; i<=n; i++) if(i % p) ans = (LL)ans * i % s;
40 
41     return (LL)ans * Calc(n / p, p, t) % s;
42 }
43 LL C(LL n, LL m, LL p, LL t) {
44     LL s = Pow(p, t), q = 0;
45     for(LL i=n; i; i/=p) q += i / p;
46     for(LL i=m; i; i/=p) q -= i / p;
47     for(LL i=n-m; i; i/=p) q -= i / p;
48 
49     LL ans = Pow(p, q);
50     LL a = Calc(n, p, t), b = Calc(m, p, t), c = Calc(n-m, p, t);
51     return (LL)(ans * a * rev(b, s) * rev(c, s)) % s;
52 }
53 LL China(LL A[], LL M[], LL cnt) {
54     LL ans = 0, m, n = 1;
55     for(LL i=1; i<=cnt; i++) n *= M[i];
56     for(LL i=1; i<=cnt; i++) {
57         m = n / M[i];
58         exgcd(M[i], m);
59         ans = (ans + (LL)y * m * A[i]) % n;
60     }
61     return (ans + n) % n;
62 }
63 LL A[maxn], M[maxn], cnt;
64 LL Lucas(LL n, LL m, LL mod) {
65     for(LL i=2; i*i <= mod; i++) if(mod % i == 0) {
66         LL t = 0;
67         while(mod % i == 0) t++, mod /= i;
68         M[++cnt] = Pow(i, t);
69         A[cnt] = C(n, m, i, t);
70     }if(mod > 1) {
71         M[++cnt] = mod;
72         A[cnt] = C(n, m, mod, 1);
73     }
74     return China(A, M, cnt);
75 }
76 LL n, k, p;
77 int main() {
78     cin >> n >> k >> p;
79     cout << Lucas(n, k, p) << endl;
80     return 0;
81 }

然后补充一个内容,线性时间复杂度内求出所有的逆元

A[i] = -(p / i) * A[p % i];

 

posted @ 2018-09-26 19:59  静听风吟。  阅读(266)  评论(0编辑  收藏  举报