知识点 - n!%p n!中k的幂次
解决问题类型:
结论、代码与复杂度:
-
计算n!%p
p很大时,如果n也很大,就用威尔逊定理: O ( p − n ) O(p-n) O(p−n).
( p − 1 ) ! + 1 ≡ 0 ( m o d p ) (p-1)!+1\equiv 0(mod\ p) (p−1)!+1≡0(mod p)
然后计算 n ∗ . . . ∗ ( p − 1 ) n*...*(p-1) n∗...∗(p−1)的逆元,用它乘-1。p较小时:
O ( p log p n ) O(p \log_p n) O(plogpn).
int factmod(int n, int p) { int res = 1; while (n > 1) { res = (res * ((n/p) % 2 ? p-1 : 1)) % p; for (int i = 2; i <= n%p; ++i) res = (res * i) % p; n /= p; } return res % p; }
-
n n n 的阶乘中 p p p 的幂次为
O ( l o g n ) O(logn) O(logn)
∑ r = 1 + ∞ [ n p r ] \sum_{r=1}^{+\infin}\left[\frac{n}{p^r}\right] r=1∑+∞[prn]int fact_pow (int n, int k) { int res = 0; while (n) { n /= k; res += n; } return res; }
例题
n!%p,n是小于p的第一个质数 :就用结论1即可
CodeForces - 1114C : 输出n!在p进制下末尾有几个0
代码
//如果 是素数,用讲义里的6.1.3定理即可求得答案
//现在 不是素数,那就分解成素数的乘积再求
#include <bits/stdc++.h>
#define rep(i,a,b) for(ll i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll fac[1005], num[1005], tot, t[1005];
void getfac(ll n) {
tot = 0; ll temp = n;
for (ll i = 2; i*i <= temp; i++) {
if (n%i == 0) {
fac[++tot] = i;
num[tot] = 0;
while (n%i == 0)num[tot]++, n /= i;
}
}
if (n>1)fac[++tot] = n, num[tot] = 1;
}
int main() {
ll n, b;
while (cin >> n >> b) {
getfac(b);
rep(i, 1, tot)t[i] = 0;
rep(i, 1, tot) {
ll now = fac[i];
while (1) {
t[i] += n / now;
if ((long double)now - 1>(long double)n / fac[i])break;
now *= fac[i];
}
}
ll ans = t[1];
rep(i, 1, tot)ans = min(ans, t[i] / num[i]);
cout << ans << endl;
}
return 0;
}