数论 · exLucas 定理
前言
终于看懂了!!!连夜丢掉卡特兰来做了两道 exLucas 的题目。
定理
作为一个没什么用的铺垫:数论 · Lucas 定理
求解
证明
1
先把
然后逐一求解
最后用 CRT 求解
2
假设求解
有
所以就变成求解
但是因为分母部分需要逆元,有可能
假设
则变为求解
3
考虑求解
先举个例子:
设
先把
按照 2 的后半部分所述,
而柿子的后半部分
对于柿子的前半部分,会发现它对
所以只用求出第一个周期:
然后就会发先剩下个
4
关于 2 中
小奥中学过试除法(忘了叫啥),可以求解类似“100 的阶乘中有多少个因子 5”的问题。
这里直接除然后求出
代码如下:
int al = n;
while(al)
k += al / pi, al /= pi;
al = m;
while(al)
k -= al / pi, al /= pi;
al = n - m;
while(al)
k -= al / pi, al /= pi;
最后用 扩展欧几里得 求出
5
关于使用 CRT 合并。
每次求完
先给代码:ans += bi * inv(p / pi, pi) % p * (p / pi) % p
bi * inv(p / pi, pi) % p 是为了让它在取模
* (p / pi) % p 是为了让它在取模其他质数的情况下余数为 0。
详见 CRT。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define int long long
#define rep(i, a, b) for(int i = a; i <= b; ++i)
int n, m, p;
inline int power(int x, int t, int mod)
{
int res = 1;
while(t >= 1)
{
if(t & 1)
res = res * x % mod;
t /= 2, x = x * x % mod;
}
return res;
}
inline int fac(int nw, int pi, int pk)
{
if(!nw) return 1;
int res = 1;
rep(i, 2, pk)
if(i % pi) res = res * i % pk;
res = power(res, nw / pk, pk);
rep(i, 2, nw % pk)
if(i % pi) res = res * i % pk;
return res * fac(nw / pi, pi, pk) % pk;
}
int x, y;
inline void exGcd(int a, int b)
{
if(!b)
{
x = 1, y = 0;
return;
}
exGcd(b, a % b);
int tmp = x;
x = y, y = tmp - a / b * y;
return;
}
inline int inv(int nw, int mod)
{
exGcd(nw, mod);
return (x + mod) > mod ? x : x + mod;
}
inline int C(int pi, int pk)
{
int fn = fac(n, pi, pk), fm = fac(m, pi, pk), fnm = fac(n - m, pi, pk);
int k = 0;
int al = n;
while(al)
k += al / pi, al /= pi;
al = m;
while(al)
k -= al / pi, al /= pi;
al = n - m;
while(al)
k -= al / pi, al /= pi;
return fn * inv(fm, pk) % pk * inv(fnm, pk) % pk * power(pi, k, pk) % pk;
}
inline int Crt(int bi, int mi)
{
return bi * inv(p / mi, mi) % p * (p / mi) % p;
}
inline int exLucas()
{
int pk, res = 0;
int lim = ceil(sqrt(p)), tmp = p;
rep(i, 2, lim)
{
if(tmp % i) continue;
pk = 1;
while(!(tmp % i))
tmp /= i, pk *= i;
res = (res + Crt(C(i, pk), pk)) % p;
}
if(tmp > 1)
res = (res + Crt(C(tmp, tmp), tmp)) % p;
return res;
}
signed main()
{
scanf("%lld %lld %lld", &n, &m, &p);
printf("%lld\n", exLucas());
return 0;
}
——