您的位置:首页 > 运维架构

TopCoder SRM 569 DIV2 Level3: MegaFactorialDiv2

2013-06-22 21:19 681 查看

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
[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!k
long 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 存储中间结果。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息