# 组合数取模&&Lucas定理题集

https://cn.vjudge.net/contest/231988

A : FZU-2020

(1 <= m <= n <= 10^9, m <= 10^4, m < p < 10^9, p是素数)

 1 #include<iostream>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e5 + 10;
5 ll fac[maxn];//阶乘打表
6 void init(ll p)//此处的p应该小于1e5，这样Lucas定理才适用
7 {
8     fac[0] = 1;
9     for(int i = 1; i <= p; i++)
10         fac[i] = fac[i - 1] * i % p;
11 }
12 ll pow(ll a, ll b, ll m)
13 {
14     ll ans = 1;
15     a %= m;
16     while(b)
17     {
18         if(b & 1)ans = (ans % m) * (a % m) % m;
19         b /= 2;
20         a = (a % m) * (a % m) % m;
21     }
22     ans %= m;
23     return ans;
24 }
25 ll inv(ll x, ll p)//x关于p的逆元，p为素数
26 {
27     return pow(x, p - 2, p);
28 }
29 ll C(ll n, ll m, ll p)//组合数C(n, m) % p
30 {
31     if(m > n)return 0;
32     ll up = 1, down = 1;//分子分母;
33     for(int i = n - m + 1; i <= n; i++)up = up * i % p;
34     for(int i = 1; i <= m; i++)down = down * i % p;
35     return up * inv(down, p) % p;
36 }
37 ll Lucas(ll n, ll m, ll p)
38 {
39     if(m == 0)return 1;
40     return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
41 }
42 int main()
43 {
44     ll n, m, p;
45     int T;
46     cin >> T;
47     while(T--)
48     {
49         cin >> n >> m >> p;
50         //init(p);
51         cout<<Lucas(n, m, p)<<endl;
52     }
53     return 0;
54 }

B：HDU-3944

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e4 + 10;
5 int fac[maxn][maxn], inv[maxn][maxn];//阶乘打表 逆元打表
6 int prime[maxn], pth[maxn];
7 int pow(int a, int b, int m)
8 {
9     int ans = 1;
10     a %= m;
11     while(b)
12     {
13         if(b & 1)ans = (ans % m) * (a % m) % m;
14         b /= 2;
15         a = (a % m) * (a % m) % m;
16     }
17     ans %= m;
18     return ans;
19 }
20 bool is_prime[maxn];
21 void init()
22 {
23     int n = 10000, cnt = 0;
24     for(int i = 2; i <= n; i++)is_prime[i] = 1;
25     for(int i = 2; i <= n; i++)
26     {
27         if(is_prime[i])
28         {
29             prime[++cnt] = i;
30             pth[i] = cnt;
31             for(int j = i * i; j <= n; j += i)is_prime[j] = 0;
32         }
33     }
34     //cout<<cnt<<endl;
35     for(int i = 1; i <= cnt; i++)
36     {
37         fac[i][0] = inv[i][0] = 1;
38         for(int j = 1; j < prime[i]; j++)//大于i的阶乘模上i均为0
39         {
40             fac[i][j] = fac[i][j - 1] * j % prime[i];
41             inv[i][j] = pow(fac[i][j], prime[i] - 2, prime[i]);
42         }
43     }
44 }
45
46 int C(ll n, int m, int p)//组合数C(n, m) % p
47 {
48     if(m > n)return 0;
49     if(m == n)return 1;
50     int t = pth[p];
51     return fac[t][n] * (inv[t][m] * inv[t][n - m] % p) % p;
52 }
53
54 int Lucas(int n, int m, int p)
55 {
56     //cout<<n<<" "<<m<<" "<<p<<endl;
57     if(m == 0)return 1;
58     return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
59 }
60
61 int main()
62 {
63     init();
64     int n, m, p;
65     int cases = 0;
66     while(scanf("%d%d%d", &n, &m, &p) != EOF)
67     {
68         if(m <= n / 2)
69         {
70             m = n - m;
71         }
72         ll ans = (Lucas(n + 1, m + 1, p) + m) % p;
73         printf("Case #%d: %d\n", ++cases, ans);
74     }
75     return 0;
76 }

C:ZOJ-3557

C（n - m + 1, m） % p

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e6 + 10;
5 const int mod = 1e9 + 7;
6 ll pow(ll a, ll b, ll m)
7 {
8     ll ans = 1;
9     a %= m;
10     while(b)
11     {
12         if(b & 1)ans = (ans % m) * (a % m) % m;
13         b /= 2;
14         a = (a % m) * (a % m) % m;
15     }
16     ans %= m;
17     return ans;
18 }
19 ll inv(ll x, ll p)//x关于p的逆元，p为素数
20 {
21     return pow(x, p - 2, p);
22 }
23 ll C(ll n, ll m, ll p)//组合数C(n, m) % p
24 {
25     if(m > n)return 0;
26     ll up = 1, down = 1;//分子分母;
27     for(int i = n - m + 1; i <= n; i++)up = up * i % p;
28     for(int i = 1; i <= m; i++)down = down * i % p;
29     return up * inv(down, p) % p;
30 }
31 ll Lucas(ll n, ll m, ll p)
32 {
33     if(m == 0)return 1;
34     return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
35 }
36 int main()
37 {
38     ll n, m, p;
39     while(cin >> n >> m >> p)
40     {
41         if(n - m + 1 < m)
42             cout<<"0"<<endl;
43         else cout<<Lucas(n - m + 1, m, p)<<endl;
44     }
45     return 0;
46 }

D在F介绍完之后再介绍

E：hdu-4349

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e6 + 10;
5 const int mod = 1e9 + 7;
6 int lowbit(int x)
7 {
8     return x & (-x);
9 }
10 int main()
11 {
12     ll n, m, p;
13     while(cin >> n)
14     {
15         int tot = 0;
16         while(n)
17             n -= lowbit(n), tot++;
18         cout<<(1<<tot)<<endl;
19     }
20     return 0;
21 }

F：Gym - 100633J

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e6 + 10;
5 const int mod = 1e9 + 7;
6 ll pow(ll a, ll b, ll m)
7 {
8     ll ans = 1;
9     a %= m;
10     while(b)
11     {
12         if(b & 1)ans = (ans % m) * (a % m) % m;
13         b /= 2;
14         a = (a % m) * (a % m) % m;
15     }
16     ans %= m;
17     return ans;
18 }
19 ll extgcd(ll a, ll b, ll& x, ll& y)
20 //求解ax+by=gcd(a, b)
21 //返回值为gcd(a, b)
22 {
23     ll d = a;
24     if(b)
25     {
26         d = extgcd(b, a % b, y, x);
27         y -= (a / b) * x;
28     }
29     else x = 1, y = 0;
30     return d;
31 }
32 ll mod_inverse(ll a, ll m)
33 //求解a关于模上m的逆元
34 //返回-1表示逆元不存在
35 {
36     ll x, y;
37     ll d = extgcd(a, m, x, y);
38     return d == 1 ? (m + x % m) % m : -1;
39 }
40
41 ll Mul(ll n, ll pi, ll pk)//计算n! mod pk的部分值  pk为pi的ki次方
42 //算出的答案不包括pi的幂的那一部分
43 {
44     if(!n)return 1;
45     ll ans = 1;
46     if(n / pk)
47     {
48         for(ll i = 2; i <= pk; i++) //求出循环节乘积
49             if(i % pi)ans = ans * i % pk;
50         ans = pow(ans, n / pk, pk); //循环节次数为n / pk
51     }
52     for(ll i = 2; i <= n % pk; i++)
53         if(i % pi)ans = ans * i % pk;
54     return ans * Mul(n / pi, pi, pk) % pk;//递归求解
55 }
56
57 ll C(ll n, ll m, ll p, ll pi, ll pk)//计算组合数C(n, m) mod pk的值 pk为pi的ki次方
58 {
59     if(m > n)return 0;
60     ll a = Mul(n, pi, pk), b = Mul(m, pi, pk), c = Mul(n - m, pi, pk);
61     ll k = 0, ans;//k为pi的幂值
62     for(ll i = n; i; i /= pi)k += i / pi;
63     for(ll i = m; i; i /= pi)k -= i / pi;
64     for(ll i = n - m; i; i /= pi)k -= i / pi;
65     ans = a * mod_inverse(b, pk) % pk * mod_inverse(c, pk) % pk * pow(pi, k, pk) % pk;//ans就是n! mod pk的值
66     ans = ans * (p / pk) % p * mod_inverse(p / pk, pk) % p;//此时用剩余定理合并解
67     return ans;
68 }
69
70 ll Lucas(ll n, ll m, ll p)
71 {
72     ll x = p;
73     ll ans = 0;
74     for(ll i = 2; i <= p; i++)
75     {
76         if(x % i == 0)
77         {
78             ll pk = 1;
79             while(x % i == 0)pk *= i, x /= i;
80             ans = (ans + C(n, m, p, i, pk)) % p;
81         }
82     }
83     return ans;
84 }
85
86 int main()
87 {
88     ll n, m, p;
89     while(cin >> n >> m >> p)
90     {
91         cout<<Lucas(n, m, p)<<endl;
92     }
93     return 0;
94 }

D：HDU-4373

同的部分，每一个部分由第一类循环开始，最终结果相乘即可。剩下的就是第二类循环的问题，假设一个

层循环，最大到，分析一下得到如下结果

（1）只有一层，则循环次数为

（2）只有前两层，则循环次数为

（3）只有前三层，则循环次数为

由此得到结论：第的循环次数为

ans按照上述公式就可以直接算出来了。

 1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const int maxn = 1e6 + 10;
5 ll pow(ll a, ll b, ll m)
6 {
7     ll ans = 1;
8     a %= m;
9     while(b)
10     {
11         if(b & 1)ans = (ans % m) * (a % m) % m;
12         b /= 2;
13         a = (a % m) * (a % m) % m;
14     }
15     ans %= m;
16     return ans;
17 }
18 const ll mod1 = 97;
19 const ll mod2 = 3761599;
20 const ll mod = mod1 * mod2;
21 ll fac1[mod1 + 10], fac2[mod2 + 10];
22 ll inv1, inv2;
23 void init()
24 {
25     fac1[0] = fac2[0] = 1;
26     for(int i = 1; i < mod1; i++)fac1[i] = fac1[i - 1] * i % mod1;
27     for(int i = 1; i < mod2; i++)fac2[i] = fac2[i - 1] * i % mod2;
28     inv1 = pow(mod2, mod1 - 2, mod1);//mod1 模上mod2的逆元
29     inv2 = pow(mod1, mod2 - 2, mod2);//mod2 模上mod1的逆元 求出在之后的中国剩余定理合并的时候不用计算
30 }
31
32 ll C(ll n, ll m, ll p, ll fac[])
33 {
34     if(m > n)return 0;
35     return fac[n] * pow(fac[m] * fac[n - m], p - 2, p) % p;
36 }
37
38 ll Lucas(ll n, ll m, ll p, ll fac[])
39 {
40     if(m == 0)return 1;
41     return C(n % p, m % p, p, fac) * Lucas(n / p, m / p, p, fac) % p;
42 }
43 int main()
44 {
45     ll n, m, k, cases = 0;
46     ll a[20];
47     int T;
48     init();
49     cin >> T;
50     while(T--)
51     {
52         cin >> n >> m;
53         cin >> k;
54         for(int i = 0; i < k; i++)cin >> a[i];
55         a[k] = m;
56         ll ans = 1;
57         for(int i = 1; i <= k; i++)
58         {
59             ll t = a[i] - a[i - 1];
60             ll a1 = Lucas(n + t - 1, t, mod1, fac1);
61             ll a2 = Lucas(n + t - 1, t, mod2, fac2);
62             ll a3 = (a1 * mod2 % mod * inv1 + a2 * mod1 % mod * inv2) % mod;//中国剩余定理合并同余方程组
63             ans = ans * a3 % mod;
64         }
65         cout<<"Case #"<<++cases<<": "<<ans<<endl;
66     }
67     return 0;
68 }

posted @ 2018-05-29 16:30  _努力努力再努力x  阅读(415)  评论(0编辑  收藏  举报