组合数_卢卡斯定理_费马小定理_高精度组合数
Posted 一只特立独行的猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组合数_卢卡斯定理_费马小定理_高精度组合数相关的知识,希望对你有一定的参考价值。
注:当遇到
(
a
/
b
)
m
o
d
p
(a/b)mod\\ p
(a/b)mod p的形式时,采用
a
∗
p
−
1
m
o
d
p
a*p^{-1}mod\\ p
a∗p−1mod p进行计算。计算
p
−
1
p^{-1}
p−1时,由于p是质数,采用费马小定理计算
p
−
1
p^{-1}
p−1。
组合数问题1:
当求的数较小,但是求得次数较多时,采用打表的方式进行记录查询。
#include<iostream>
using namespace std;
const int N = 1e5+5,mod = 1e9+7;;
typedef long long LL;
LL fac[N],infac[N];
LL qmi(LL a,LL p,LL q){
//快速幂求逆元
LL res =1;
while(p){
if(p&1) res=res*a%q;
a=a*a%q;
p>>=1;
}
return res;
}
int main(){
fac[0]=infac[0]=1;
for(int i=1;i<N;i++){
fac[i]=fac[i-1]*i%mod;
infac[i]=(LL)infac[i-1]*qmi(i,mod-2,mod)%mod;
}
int n;
cin>>n;
while(n--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\\n",fac[a]*infac[b]%mod*infac[a-b]%mod);
}
return 0;
}
组合数问题2:
当数较大,但是查询次数较少时,采用卢卡斯定理进行计算。
卢卡斯定理:
C
a
b
三
C
a
m
o
d
p
b
m
o
d
p
∗
C
a
/
p
b
/
p
(
m
o
d
p
)
C^b_a三C^{b\\ mod \\ p}_{a\\ mod \\ p}*C^{b / p}_{a/ p}(mod\\ p)
Cab三Ca mod pb mod p∗Ca/pb/p(mod p)
#include<iostream>
using namespace std;
typedef long long LL;
int p;
LL qmi(LL a, LL k) {
//快速幂求逆元
LL res = 1;
while (k) {
if (k & 1) res = res * a % p;
k >>= 1;
a = a * a % p;
}
return res;
}
LL C(LL a, LL b) {
//计算组合数
LL res = 1;
for (int i = b; i >= 1; i--) {
res = res * a % p;
res = res * qmi(i, p - 2) % p;
a--;
}
return res;
}
LL locas(LL a, LL b) {
//当b<p的时候,说明locas(a / p, b / p) % p=1
if (b < p) return C(a % p, b % p);
return C(a % p, b % p)* locas(a / p, b / p) % p;
}
int main() {
int n;
cin >> n;
while (n--) {
LL a, b;
cin >> a >> b >> p;
cout<<locas(a, b)<<endl;
}
return 0;
}
组合数问题3:
高精度组合数。思路:通过对分子分母进行分解质因数,然后上下的质因数消去一部分,就可以得到最终的解。
a阶乘分解质因数中p的指数是
a
p
+
a
p
2
+
.
.
.
\\frac a p +\\frac a p^2 +...
pa+pa2+...其中
/
/
/是整除的意思
#include<iostream>
#include<vector>
using namespace std;
const int N = 5e5 + 5;
int prime[N], cnt;
bool st[N];
int sum[N];
void get_prime(int n) {
\\\\线性筛筛素数
for (int i = 2; i <= n; i++) {
if (!st[i]) prime[cnt++] = i;
for (int j = 0; prime[j] <= n / i; j++) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
int get(int a, int p) {
//得到a!中p质因子的个数
int res = 0;
while (a) {
res += a / p;
a /= p;
}
return res;
}
vector<int > mul(vector<int > a, int b) {
//高精度乘法
vector<int> k;
int t = 0;
for (int i = 0; i < a.size(); i++) {
t += a[i] * b;
k.push_back(t % 10);
t /= 10;
}
while (t != 0) {
k.push_back(t % 10);
t /= 10;
}
return k;
}
int main() {
int a, b;
cin >> a >> b;
get_prime(a);//线性筛求素数的个数
for (int i = 0; i < cnt; i++) {
sum[i] = get(a, prime[i]) - get(b, prime[i]) - get(a - b, prime[i]);
}
vector<int> ans;//0是低位
ans.push_back(1);
for (int i = 0; i < cnt; i++) {
for (int j = 0; j < sum[i]; j++) {
ans = mul(ans, prime[i]);
}
}
for (auto it = ans.rbegin(); it != ans.rend(); it++) {
cout << *it;
}
return 0;
}
以上是关于组合数_卢卡斯定理_费马小定理_高精度组合数的主要内容,如果未能解决你的问题,请参考以下文章