HDU 4542:小明系列故事——未知剩余系

点击打开题目链接

题目是中文题目,但是还是有点绕的。

题目意思:

每次给出两个数 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;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值