题目地址
http://acm.bnu.edu.cn/bnuoj/external/57/5772.pdf
题目大意:
给一个数字n (n < 75)。求最小的X , 满足 X = Y * Z (Y <= Z) 有n种方式
分析:
此题跟我航出的Anti-Prime 反素数的题目类似, 都是直接搜索+枚举答案就好。
解法:
0、 筛法求素数。 因为n <= 75 , 因此理论上只用求出前75个(或者更小就不细算了) 质数就行。
1、对一般情况的判定(不包括 X = Y * Y 即平方数的问题)
显而易见, 如果 X != Y * Y , 那么X肯定会有 N * 2 个因数。因此,只要枚举最小的有 M (= N * 2 )个因数的数就可以。方法是搜索:
dfs(LL now , LL step , LL cnt) 状态是 当前的乘积是 now , 已经步行到第step个素数(2 , 3 , 5 , 7 , 11 , 13.。。。), 现在一共有cnt个因数。
对于第step个因数, 如果有k个, 即下一个状态是 now * $ prime[step] ^{k} $ 时, 很明显因数个数增加了(k + 1) 倍,于是下一个状态就是
dfs(now * $ prime[step] ^{k} $ , step + 1 , cnt * (k + 1) )
剪枝:
初始化ans = $2^{18}$ , (题目保证了答案一定小于等于这个数) , 然后对于每次转移时 , 如果 now * prime[step] > ans 的时候break
2、对于平方数的情况, 不妨考虑这两个数:4 , 36
4 = 1 * 4 = 2 * 2 = (分解质因数为) $2^{2}$ , 按照先前的算法应该有 2 + 1 = 3个因数,而 n = 2
36 = 1 * 36 = 2 * 18 = 3 * 12 = 4 * 9 = 6 * 6 = (分解质因数为) $2^{2}*3^{2}$ , 按照先前的算法应该是有 (2 + 1)* (2+ 1) = 9 个因数,而 n = 5
为什么呢?因为对于n来说,有两个因数重合。那么对于平方数来说,只需要 n * 2 - 1 个因数就可以。因为必须是完全平方数,于是每个因数的幂就必须是偶数。只用在搜索的时候特判就好了。
至此,这个问题就被完美的解决了。
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define LL long long
const int PRIMERANGE = 300;
const LL inf = 1e18;
int prime[PRIMERANGE + 1];
int getPrime(){ // 筛法求素数, 模板
memset(prime , 0 , sizeof(prime));
for (int i = 2 ; i <= PRIMERANGE ;++i){
if (!prime[i]) prime[++prime[0]] = i;
for (int j = 1 ; j <= prime[0] && prime[j] <= PRIMERANGE / i ; j++){
prime[prime[j] *i ] = 1;
if (i % prime[j] == 0) break;
}
}
return prime[0];
}
LL n;
LL ans;
void dfs(LL now , LL step, LL cnt){ // 不考虑平方的情况
if (cnt == n){
ans = min<LL>(ans , now); //记录当前最佳答案
return;
}
LL last = n / cnt;
for(LL i = 1 ; i <= last ; ++i){ // 枚举prime[step]的幂
if (prime[step] * now > ans) break; //剪枝
now *= prime[step];
if (last % (i + 1 )) continue; // 剪枝, 如果 cnt * (i + 1) 不是n的约数那么放弃
dfs(now , step + 1 , cnt* (i + 1)); // 状态转移
}
}
void dfssquare(LL now , LL step, LL cnt){ // 特判完全平方数
if (cnt == n){
ans = min<LL>(ans , now);
return;
}
LL last = n / cnt;
for(LL i = 2 ; i <= last ; i += 2){ // 幂必须为偶数
if (now * prime[step] > ans) break;
now *= prime[step] * prime[step];
//if (now > ans) break;
if (last % (i + 1 )) continue;
dfssquare(now , step + 1 , cnt* (i + 1));
}
}
void solve(){
n*= 2; // 忽略完全平方数的情况
ans = inf;
dfs(1 , 1 , 1);
LL other = ans;
ans = inf;
n /= 2; // 特判完全平方数
n = 2 * n - 1;
dfssquare(1 , 1 , 1);
ans = min<LL>(ans , other); // 答案取小
printf("%I64d\n" , ans);
}
int main(){
getPrime();
while(cin >> n , n) solve();
}