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,6Solution: 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 存储中间结果。 |
相关文章推荐
- topcoder SRM 500 div2 level3
- topcoder SRM 492 div2 level3
- Topcoder SRM 628 DIV 2
- [topcoder]SRM 647 DIV 2
- TopCoder SRM 677 Div. 2 550 - FourStrings (枚举)
- [TopCoder] SRM 580 DIV 2, 250p, 500p, 1000p, Solution
- [TopCoder] SRM_594_DIV2.250
- topcoder srm 704 div1
- TopCoder SRM 606 Div2 题解
- topcoder SRM 637 DIV2题解
- TopCoder SRM 446 DIV2 500points
- 【TopCoder】SRM160 DIV1总结
- topcoder srm 713 div1 -3
- 【动态规划】TopCoder SRM 573 division2 WolfPackDivTwo
- topcoder srm 695 div1 -3
- topcoder srm 691 div1 -3
- topcoder srm 495 div1
- topcoder srm 510 div1
- topcoder srm 684 div1 -3
- TopCoder——SRM 516 DIV 2