数论-组合数

组合数一:

组合数范围小,询问多,可以采用预处理方式,把所有的都处理出来

题目:

给定nn组询问,每组询问给定两个整数a,ba,b,请你输出Cba mod (109+7)Cab mod (109+7)的值。

输入格式

第一行包含整数nn。

接下来nn行,每行包含一组aa和bb。

输出格式

共nn行,每行输出一个询问的解。

数据范围

1≤n≤100001≤n≤10000,
1≤b≤a≤20001≤b≤a≤2000

输入样例:

3
3 1
5 3
2 2

输出样例:

3
10
1

 1 #include <iostream>
 2 using namespace std;
 3
 4 const int N = 2010;
 5 const int mod = 1e9+7;
 6
 7 int c[N][N];
 8
 9 void init(){
10     for(int i = 0;i < N;++i)
11         for(int j = 0;j <= i;++j)
12             if(j == 0) c[i][j] = 1;
13             else c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;//记住这个公式
14 }
15
16 int main(){
17     init();
18     int n;cin >> n;
19     while(n --){
20         int a, b;cin >> a >> b;
21         cout << c[a][b] << endl;
22     }
23     return 0;
24 }

组合数二:

组合数范围大,询问也很多,可以采用组合数公式,此时需要用到乘法逆元

题目:

给定nn组询问,每组询问给定两个整数a,ba,b,请你输出Cba mod (109+7)Cab mod (109+7)的值。

输入格式

第一行包含整数nn。

接下来nn行,每行包含一组aa和bb。

输出格式

共nn行,每行输出一个询问的解。

数据范围

1≤n≤100001≤n≤10000,
1≤b≤a≤1051≤b≤a≤105

输入样例:

3
3 1
5 3
2 2

输出样例:

3
10
1

 1 #include <iostream>
 2 using namespace std;
 3
 4 typedef long long ll;
 5 const int N = 1e5+10;
 6 const int mod = 1e9+7;
 7
 8 ll fact[N], infact[N];//fact存的是阶乘,infact存的是阶乘的逆元
 9
10 ll qmi(ll a, ll k, ll p){
11     ll res = 1;
12     while (k)
13     {
14         if (k & 1) res = res * a % p;
15         a = a * a % p;
16         k >>= 1;
17     }
18     return res;
19 }
20
21 int main(){
22     fact[0] = infact[0] = 1;
23     for(int i = 1;i < N;++i){
24         fact[i] = i * fact[i - 1] % mod;
25         infact[i] = qmi(fact[i], mod - 2, mod) % mod;
26     }
27     int n;cin >> n;
28     while(n --){
29         int a, b;cin >> a >> b;
30         cout << fact[a]*infact[b]%mod*infact[a-b]%mod << endl;
31     }
32     return 0;
33 }

组合数三:

询问少,但是组合数范围巨大,采用卢斯卡定理,

组合数定义式:       

题目:

给定nn组询问,每组询问给定三个整数a,b,pa,b,p,其中pp是质数,请你输出Cba mod pCab mod p的值。

输入格式

第一行包含整数nn。

接下来nn行,每行包含一组a,b,pa,b,p。

输出格式

共nn行,每行输出一个询问的解。

数据范围

1≤n≤201≤n≤20,
1≤b≤a≤10181≤b≤a≤1018,
1≤p≤1051≤p≤105,

输入样例:

3
5 3 7
3 1 5
6 4 13

输出样例:

3
3
2

 1 #include <iostream>
 2 using namespace std;
 3
 4 typedef long long ll;
 5
 6 ll qmi(ll a, ll k, ll p){
 7     ll res = 1;
 8     while (k)
 9     {
10         if (k & 1) res = res * a % p;
11         a = a * a % p;
12         k >>= 1;
13     }
14     return res;
15 }
16
17 ll C(ll a, ll b, ll p){
18     if(b > a) return 0;
19     ll x = 1, y = 1;
20     for(int i = 0; i < b; i++)//定义式
21     {
22         x = x * (a - i) % p;
23         y = y * (i + 1) % p;
24     }
25     return x * qmi(y, p - 2, p) % p;//x是分子,y是分母,分母用到了逆元
26 }
27
28 ll lusca(ll a, ll b, ll p){
29     if(a < p && b < p) return C(a, b, p);
30     return C(a%p, b%p, p) * lusca(a/p, b/p, p) % p;//公式
31 }
32
33 int main(){
34     int n;cin >> n;
35     while(n --){
36         ll a, b, p;cin >> a >> b >> p;
37         cout << lusca(a, b, p) << endl;
38     }
39     return 0;
40 }

组合数四:

求出来的结果很大,需要用到高精度

题目:

输入a,ba,b,求CbaCab的值。

注意结果可能很大,需要使用高精度计算。

输入格式

共一行,包含两个整数aa和bb。

输出格式

共一行,输出CbaCab的值。

数据范围

1≤b≤a≤50001≤b≤a≤5000

输入样例:

5 3

输出样例:

10

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int N = 5010;
 5
 6 int prime[N], cnt;
 7 bool st[N];
 8 int sum[N];
 9
10
11 void get_prime(int n){
12     for(int i = 2;i <= n;++i){
13         if(!st[i]){
14             prime[cnt++] = i;
15             for(int j = i + i;j <= n;j += i) st[j] = true;
16         }
17     }
18 }
19 //看a的阶乘里有多少个p
20 int get(int a, int p){
21     int res = 0;
22     while(a){
23         res += a / p;
24         a /= p;
25     }
26     return res;
27 }
28 //高精度乘法
29 vector<int> mul(vector<int>& a, int b){
30     vector<int> res;
31     int t = 0;
32     for(int i = 0;i < a.size();++i){
33         t += a[i] * b;
34         res.push_back(t % 10);
35         t /= 10;
36     }
37     while(t){
38         res.push_back(t % 10);
39         t /= 10;
40     }
41     return res;
42 }
43
44 int main(){
45     int a, b;cin >> a >> b;
46     get_prime(a);//获取所有质数
47     //枚举每个质数,看看结果里有多个该质数
48     for(int i = 0;i < cnt;++i){
49         int t = prime[i];
50         sum[i] = get(a, t) - get(b, t) - get(a - b, t);
51     }
52     //求结果
53     vector<int> ans;
54     ans.push_back(1);
55     for(int i = 0;i < cnt;++i)
56         for(int j = 0;j < sum[i];++j)
57             ans = mul(ans, prime[i]);
58
59     for(int i = ans.size()-1;i >= 0;--i) printf("%d", ans[i]);
60     return 0;
61 }



原文地址:https://www.cnblogs.com/sxq-study/p/12275986.html

时间: 2024-11-02 08:36:04

数论-组合数的相关文章

# 数论-组合数+lacus定理

目录 数论-组合数+lacus定理 组合数计算 lacus定理-大组合数取模 数论-组合数+lacus定理 组合数计算 为避免爆long long,\(20!\)就达到了long long 的范围,采用边乘边除的思想 ll C(ll n,ll m){ if(n<m)return 0; ll ans=1; for(ll i=1;i<=m;i++) ans=ans*(n-m+i)/i; return ans; } lacus定理-大组合数取模 卢卡斯定理:C(n,m)%p=C(n/p,m/p)*C

ACM数论之旅10---大组合数-卢卡斯定理(在下卢卡斯,你是我的Master吗?(。-`ω&#180;-) )

记得前几章的组合数吧 我们学了O(n^2)的做法,加上逆元,我们又会了O(n)的做法 现在来了新问题,如果n和m很大呢, 比如求C(n, m) % p  , n<=1e18,m<=1e18,p<=1e5 看到没有,n和m这么大,但是p却很小,我们要利用这个p (数论就是这么无聊的东西,我要是让n=1e100,m=1e100,p=1e100你有本事给我算啊(°□°),还不是一样算不出来) 然后,我们著名的卢卡斯(Lucas)在人群中站了出来(`?д?´)说:“让老子来教你这题” 卢卡斯说:

数论简单题 组合数

本人水平有限,题解不到为处,请多多谅解 本蒟蒻谢谢大家观看 题目: 数论简单题 (simple.cpp/in/out 1s 256M) 由于最终结果可能超过int的范围,因此请将运算结果对1000000007取模. Input 第1行,一个整数T(T <= 200000),表示数据组数. 第2行至第T+1行,每行两个整数m, n. 0 < m <= n <= 2000 Output 共T行,每行输出一个整数,代表求和结果. Sample Input 3 1 1 2 3 3 3 Sa

数论篇7——组合数 &amp; 卢卡斯定理(Lucas)

组合数 组合数就是高中排列组合的知识,求解组合数C(n,m),即从n个相同物品中取出m个的方案数. 求解方式 求解通式:$C^{m}_{n}=\dfrac {n!}{m!\left( n-m\right) !}$ 性质1:$C^{m}_{n}=C_{n}^{n-m}$ 性质2:$C^{m}_{n}=C^{m-1}_{n-1}-i+C^{m}_{n-1}$ 打表递推 根据性质2:$C^{m}_{n}=C^{m-1}_{n-1}+C^{m}_{n-1}$ 组合数算出来特别大,往往都会要求取余,这里取

CF895C Square Subsets (组合数+状压DP+简单数论)

题目大意:给你一个序列,你可以在序列中任选一个子序列,求子序列每一项的积是一个平方数的方案数. 1<=a[i]<=70 因为任何一个大于2的数都可以表示成几个质数的幂的乘积 所以我们预处理70以内的质数,把它作为二进制状压的状态,每个在序列中出现数Hash一下,组合数推一下 所以把奇次幂的状态表示为1,偶次幂的状态就是0,比如6就是11,42就是1011 而平方数的每个质因子的指数都是偶数,所以最终结果的状态就是0000000... 转移的过程,两个数的乘积,就是这两个数的质因子二进制的状态的

【数论干货】线性方法求阶乘,逆元和组合数

线性求法,即预处理出阶乘以及逆元 阶乘的递推式非常好想,fac[i]=fac[i-1]*i fac[0]=1; for(register int i=1;i<=maxn;++i) fac[i]=(1ll*fac[i-1]*i)%mod; 至于逆元,易证inv[i]=inv[i+1]*(i+1) inv[maxn]=qpow(fac[n+m],mod-2); for(register int i=maxn-1;i>=0;--i) inv[i]=(1ll*inv[i+1]*(i+1))%mod;

【BZOJ2729】【HNOI2012】排队 组合数 数论 Python高精度

转载请注明出处谢谢:http://blog.csdn.net/vmurder/article/details/42964151 题解: 代码里面有注释. 注意: Python2中的中文字符即使注释了,也会CE(当然,因为Python是直接运行,不编译,所以显示WA) 呃,而本地的Python3就不管它了.. 所以我的代码需要删掉中文注释再交233. 代码: # n!(A(n+1,2)*A(n+3,m)+2*(n+1)*A(n+2,m-1)*m) # 首先男生随便放 这样是n!种摆法. # 然后再

CodeForces 396A 数论 组合数学

题目:http://codeforces.com/contest/396/problem/A 好久没做数论的东西了,一个获取素数的预处理跟素因子分解写错了,哭瞎了,呵呵, 首先ai最大值为10^9,n为500,最坏的情况 m最大值为500个10^9相乘,肯定不能获取m了,首选每一个ai肯定是m的一个因子,然后能分解就把ai给分解素因子,这样全部的ai都分解了  就能得到m的 所有素因子 以及 所有素因子的个数,题目求的 是n个因子的 不同序列的个数,所以每次 只能选出n个因子,这n个因子由素因子

信息学中的数论(一)

做oi题目的时候,遇到数论题会令我兴奋不已. 这一篇让我来聊一聊我学过的gcd,lcm,扩展欧几里得算法,逆元,组合数等. 这篇贴的代码都是未经过编译运行的,所以如果有错或有疑问请评论. 恩 那么什么是数论 和数学有关的非几何都是数论? 嘛,我也不知道定义,那么就草率地认为所有和数学有关的非计算几何知识都是数论吧. 我们先来聊一聊gcd. 这个东西,非常的有用. 它的名字叫最大公约数. 正常人都知道,有一个方法叫辗转相除法(证明略): int gcd(int a,int b) { if(!b)r