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

 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
", 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 }
View Code
原文地址:https://www.cnblogs.com/astoninfer/p/4811554.html