题目是中文题目,但是还是有点绕的。
题目意思:
每次给出两个数 Type,K.
Type = 0 求因子的个数为K的最小整数X,如果这个数大于2^62次方,输出INF,否则输出答案
Type = 1 求因子个数为X-K的最小整数X.
第一问其实就是求解因子个数为K的反素数。套求反素数的模板
因为最近做了一个题POJ 2886 要用到反素数这个概念,但是自己之前都不知道这个东西,只能先学反素数在做这个踢了,所以就去别人博客学习了一下
反素数的概念和来做了两道题。反素数的概念
第二问,求一个最小的X,其因子个数为X-K,则1~X中其因子个数为K
这个是看别人的题解,求解方法挺巧妙的,一开始还没看懂,不过后来就明白了,采用的方法是打表,设置数组,d[ ]
最开始d[i]初始化为i,在1~i中,i的因子个数为i-k,则i的非因子个数为K,因此对于i来说,i的倍数都要减去1,减去i这个因子
当求出d[i[后,d[i]代表1~i中i的非因子个数。如果d[d[i]] == 0 ,d[d[i]] = i ,直接将d[i]与i映射。然后让d[i] = 0。代表这个位置所
映射的答案还未找出。
AC代码:
#include <iostream>
#include <stdio.h>
using namespace std;
typedef unsigned long long ull;
#define INF ((ull)1)<<62
const int maxn = 50000;
ull ans;
int Type,K;
int d[maxn]; ///d[i]存放的是非约数个数为k的最小数值。
///制素数表
int prime[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,47,53};
///这里难理解,看别人的好久才明白,只能说很巧妙
void create_table()
{
///d[i]最先存储的是i的非因子的个数
for(int i = 1; i < maxn; i++)
d[i] = i;
for(int i = 1; i < maxn; i++)
{
for(int j = i; j < maxn; j += i)
d[j]--; ///i的倍数都要减减
///第i个数的非因子个数已经求出
if(!d[d[i]])
d[d[i]] = i;
/**这一步原来d[i]存放的是1~i内对于i的非因子个数为K,
如果d[k]的位置没有数,则当前i值就是答案,否则i是从小到大进行循环的,
如果d[K]的位置不等于0,说明之前已经有数占据这个位置了,那个数还比当前
i小,不用更新。每次都把d[i]赋值为0**/
d[i] = 0;
}
}
///求因子个数为K的最小数x,即求反素数
void dfs(int pos,ull value,int num)
{
if(num > K || pos > 15)
return;
if(num == K)
{
ans = min(ans,value);
return;
}
for(int i = 1; i <= 63; i++)
{
if(value > ans/prime[pos] || num*(i+1)>K)
break;
value *= prime[pos];
if(K%(num*(i+1))==0)
dfs(pos+1,value,num*(i+1));
}
}
int main()
{
int T,t=1;
create_table(); ///先打表
cin>>T;
while(T--)
{
cin>>Type>>K;
cout<<"Case "<<t++<<": ";
///求约数个数为X-K的最小X
if(Type)
{
if(d[K])
cout<<d[K]<<endl;
else
cout<<"Illegal"<<endl;
}
else
{
ans = 1e19;
dfs(0,1,1);
if(ans > INF)
cout<<"INF"<<endl;
else
cout<<ans<<endl;
}
}
return 0;
}