TopCoder SRM 569 DIV2 Level3: MegaFactorialDiv2

来源:互联网 发布:电磁炉评测 知乎 编辑:程序博客网 时间:2024/05/22 09:00

Problem Statement

 

The factorial of the k-th order of a number n is denoted n!k and defined by the following recurrences:

1) n!k = n!(k-1) * (n-1)!k for n > 0 and k > 0

2) n!k = 1 for n = 0

3) n!k = n for k = 0

 For example, 7!1 = 7! (the traditional factorial), and 5!3 = 5!2 * 4!3 = (5!1 * 4!2) * 4!3. 

You are given ints N and K. Compute the number of distinct divisors of the numberN!K. Return the computed number modulo 1,000,000,009.

1<= N <= 1000, 1 <= K <= 100

Examples: 

N=3, K=1, ans=4. 3!1 = 6, 6的因子分别为1,2,3,6

Solution:

1)

4!0 = 4

4!1 = 4!0 * 3!0 * 2!0 * 1!0   

     = 4!   

     = 4 * 3 * 2 * 1   

4!2 = 4!1 * 3!1 * 2!1 * 1!1   

      = (4 * 3 * 2 * 1) * (3 * 2 * 1) * (2 * 1) * 1   

      = (4) * (3*3) * (2*2*2) * (1*1*1*1)   

4!3 = 4!2 * 3!2 * 2!2 * 1!2   

      = (4!1 * 3!1 * 2!1 * 1!1) * (3!1 * 2!1 * 1!1) * (2!1 * 1!1) * (1!1)   

      = (4!1) * (3!1)2 * (2!1)3 * (1!1)4   

      = 4*3*2*1 *  (3*2*1)2 * (2*1)3 * (1*1*1*1)   

      = (4) * (3*3*3) * (2*2*2*2*2*2) * (1*1*1*1*1*1*1*1*1*1)   

      = 41 * 33 * 26 * 110

可以看出 N!K = N^f(N,N,K)*(N-1)^f(N-1,N,k)*...X^f(X,N,K)...2^f(2,N,K)*1^f(1,N,K),f(X,N,K) 表示X在N!K连乘中出现的次数, 1<=X<=N, 当X>N时, f(X, N, K) = 0。

 例如 4!1= 4!= 4 * 3* 2 *1,则f(4,4,1)= 1,f(X,N,1) = 1;

4!3 = 41 * 33 * 26 * 110, 则f(3,4,3) = 3, f(2,4,3) = 6.

因为n!k = n!(k-1) * (n-1)!k, 所以f(X,N,K) = f(X, N, K-1) + f(X, N-1, K).

2<=X=N, 1<= k <=K, f(X,1,k) = 0;

1<= n <=N; x<=n f(X,n, 1) = 1, x > n f(X, n, 1) = 0,

可以递推求得f(X,N,K)值,时间复杂度O(X*N*K), 因为X<=N,所以为O(N^2*K)。

其实对于公式f(X,N,K) = f(X, N, K-1) + f(X, N-1, K)来说,X值并不改变,f(x, n, k)  = f(x+1, n+1, k)= f(x+T, n+T, k)

这样只需要计算出f(2, n, k), f(x,n,k) = f(2, n-x+2, k), 这样时间复杂度降至O(N*K).

2) 对于一个正整数n, 怎样求其因子个数之和? 假设n = p1^e1 * p2^e2*...*pt^et,则因子个数之和= (e1+1)*(e2+1)*...(et+1)。其中pi表示小于等于n的所有素数。

Code

#include "stdafx.h"#include <iostream>using namespace std;int MOD = 1000000009;class MegaFactorialDiv2{long map[1001][101];bool IsPrime[1001];public:int countDivisors(int N, int K){if (N == 0){return 1;}if (K == 0){return N % MOD;}for(int n = 1; n <= N;n++){map[n][1] = 1;}for (int k = 1; k <= K; k++){map[1][k] = 0;}for (int i = 2; i <= N; i++){for(int j = 2; j <= K; j++){map[i][j] = (map[i-1][j] + map[i][j-1]) % MOD;}}long long ans = 1;for(int i = 2; i <=N; i++){IsPrime[i] = true;}for(int p = 2; p <= N; p++){if (IsPrime[p]){for(int j = 2*p; j <=N; j+=p){IsPrime[j] = false;}long e = ((primeAppears(N,K,p) + 1) % MOD);ans =  (ans * e) % MOD;if (ans < 0 ){cout << ans <<endl;}}}return (int)(ans % MOD);}// The number of times prime factor p appears in the factorization of N!klong primeAppears(int N, int K, int p){long long res = 0;// For each factor x:for (int x = 2 ; x <= N; x++) {int y = x;while ( y%p == 0) {y /= p;res += map[N-x+2][K];res = res % MOD;}}if (res < 0){cout <<res <<endl;}return (long)(res % MOD);}};int _tmain(int argc, _TCHAR* argv[]){MegaFactorialDiv2 * a = new MegaFactorialDiv2();int ans = a->countDivisors(1000, 100);cout <<ans << endl;return 0;}

总结

1. 这题主要考察动态规划和数学知识,刚开始我走进了牛角尖,一直想求出f(x,n,k)的通项公式(二项式定理),导致一直在演算,反而效果不好。

2. 这题主要的技巧在于最后X的降维,将三维将为两维,降低时间复杂度;

3. 程序中需要注意乘积溢出问题,用long long 存储中间结果。

 

原创粉丝点击