poj2992 Divisors
考虑对n!进行快速质数分解,对任意质数p,有质数p在n!中出现次数
cnt(n,p)= n / p + n / p / p +...(*)
正确性也很容易说明,由于n! = 1 * 2 *...*n, 我们只需考虑不超过n的数m对p的出现次数的贡献次数cnt(m):
m= p^k * m1,其中m1与p互质,cnt(m) = k。
那么(*)式右边第一项表示从n个数中取出含有质因子p的数的个数,
此时显然所有含有质因子p的数对等式左边贡献1,
取出的数分别为p*1, p*2,...,p*(n /p)
用p除取出的数,反复以上过程,可实得到n!中质因子p出现次数的值。
http://poj.org/problem?id=2992
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 typedef __int64 LL; 5 using namespace std; 6 const int maxn = 450; 7 int prime[maxn], k; 8 int cnt[maxn][maxn]; 9 //cnt[i][j] :: prime[j]^cnt[i][j] | i! 10 bool vis[maxn]; 11 int n, m; 12 13 void init(){ 14 k = 0; 15 memset(vis, 0, sizeof vis); 16 for(int i = 2; i < maxn; i++) if(!vis[i]){ 17 prime[k++] = i; 18 for(int j = i; j < maxn; j += i) vis[j] = 1; 19 } 20 memset(cnt, 0, sizeof cnt); 21 for(int i = 1; i < maxn; i++){ 22 for(int j = 0; j < k; j++){ 23 int cnt1 = 0, p = i; 24 while(p / prime[j]) cnt1 += p / prime[j], p /= prime[j]; 25 cnt[i][++cnt[i][0]] = cnt1; 26 } 27 } 28 } 29 30 void solve(){ 31 LL ans = 1; 32 for(int i = 1; i <= k; i++) ans *= (cnt[n][i] - cnt[m][i] - cnt[n - m][i] + 1); 33 printf("%I64d\n", ans); 34 } 35 36 int main(){ 37 //freopen("in.txt", "r", stdin); 38 init(); 39 while(~scanf("%d%d", &n, &m)) solve(); 40 return 0; 41 }