传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4542
题意:
给出一个数K,和两个操作,如果操作是0,就求出一个最小的正整数X,满足X的约数个数为K,如果操作是1,就求出一个最小的X,满足X的约数个数为X-K(或者有K个数与X互质)
思路:
对于操作0,就是求反素数,直接搜索搞定,这题时限200ms,所以要注意剪枝。
对于操作1,代表1至X中不是X的约数(互质)个数为K,暴力打表就好了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf = ((1LL) << 62) + 1;
const int N = 5e4 + 10;
int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};//这16个素数乘起来接近于ull最大值
//因为质因数的指数不递减,所以所以指数为1的时候不爆ull的最多16个质数
ll ans;
int n;
int d[N];//1~d[i]中不是d[i]约数有i个
void init(){
for(int i = 1; i < N; i++)d[i] = i; //初始化i最多有i个与其互质的数
for(int i = 1; i < N; i++){
for(int j = i; j < N; j += i) d[j]--; //i为j的因子,所以j与i不互质,第j个数的互质数减少1
if(!d[d[i]]) d[d[i]] = i;
d[i] = 0; //不大于i的数不可能存在某个数与其互质的数的个数等于i
}
}
void dfs(int dep, ll tmp, int num, int limit){
//深度,当前数的值,因数的个数,当前质因数的指数
if(num > n)return ;
//贪心,当因子个数相同时,取值最小的
if(num == n && ans > tmp) ans = tmp;
for(int i = 1; i <= limit; i++){ //指数单调不增
if(tmp > ans / p[dep] || num * (i + 1) > n)break;
tmp *= p[dep];
if(n % (num * (i + 1)) == 0) // 剪枝
dfs(dep + 1, tmp, num * (i + 1), i);
}
}
int main(){
int t, type;
init();
scanf("%d", &t);
for(int kase = 1; kase <= t; kase++){
scanf("%d%d", &type, &n);
printf("Case %d: ", kase);
if(type){
if(!d[n])puts("Illegal");
else printf("%d\n", d[n]);
}
else{
ans = inf;
dfs(0, 1, 1, 62);
if(ans == inf)puts("INF");
else printf("%I64d\n", ans);
}
}
return 0;
}