HDOJ 4542 小明系列故事——未知剩余系(反素数)

本文探讨了一种高效算法,用于解决求约数或非约数个数为特定值k的最小整数问题。通过定义反素数的概念,文章详细解释了如何利用DFS深度优先搜索来寻找满足条件的最小整数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


http://acm.hdu.edu.cn/showproblem.php?pid=4542


题意:当type = 0, 求约数有k个的最小整数,当type = 1, 求非约数有k个的最小整数。


首先考虑type = 0 的情况


反素数的定义:对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整

            数,都有,那么称为反素数。

 

从反素数的定义中可以看出两个性质:

 

(1)一个反素数的所有质因子必然是从2开始的连续若干个质数,因为反素数是保证约数个数为的这个数尽量小

(2)同样的道理,如果,那么必有


反素数为什么是保证约数个数为x的这个数n尽量小?如果有n1>……>n2,f(n1)=……=f(n2)=k,那么根据定义,n2才可能是反素数。(可能不是的原因是f(i)>f(n))

如果反素数的质因子不是连续的,那么必然有一种约数个数为x的连续情况(可以看成是指数不变,底数全部向前挪),所得的n一定比当前的小,违反了保证约数个数为x的这个数n尽量小。

如果不是t1>=t2>=t3……这样的不上升序列,那么约数个数为x的这个数n还不是最小的,同样也违反了。

约数个数为x的最小数n,一定满足(1)(2),但反之也不一定成立。

所以反素数一定满足(1)(2),但反之不一定成立。

题目中type = 0的情况,是求一个最小的数使它的约数个数为k,那么就是在满足(1)(2)的数中找最小的。可以用dfs。

type = 1时 ip[i]本来是表示i的非约数个数 后来改成了非约数个数为i的最小数为ip[i]

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL __int64
#define N 50005
using namespace std;
const int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
const LL INF = (((LL)1)<<62)+1;
LL ans;
int ip[N], k;
void Init()
{
    for(int i=1;i<N;i++) ip[i] = i;
    for(int i=1;i<N;i++)
    {
        for(int j=i;j<N;j+=i) ip[j]--;
        if(!ip[ip[i]]) ip[ip[i]] = i;
        ip[i] = 0;                                                                                                                   }                                                                                                                             }
void dfs(LL dept, LL limit, LL tmp, LL num) //当前处理第dept个质因子,limit是根据规律在限制指数,tmp是当前已累乘的数,num是当前已经产生了多少个约数 约数个数是同一个质因子出现个数+1累乘
{
    if (num == k && tmp < ans) ans = tmp;
    for (int i = 1; i <= limit; i++)
    {
        if (ans / double(p[dept]) <= tmp || num * (i+1) > k) break; // 不能写成 ans < tmp*p[dept] 会爆LL
        tmp *= p[dept];
        if (k % (num * (i+1)) == 0)
            dfs(dept+1, i, tmp, num * (i+1));
    }
}
int main()
{
    Init();
    LL tt = 1, n;
    scanf("%I64d", &n);
    while (n--)
    {
        LL T;
        scanf("%I64d%I64d", &T, &k);
        if (T == 1) ans = ip[k];
        else
        {
            ans = INF;
            dfs(0, 62, 1, 1);
        }
        printf("Case %I64d: ",tt++);
        if (ans == 0)
            printf("Illegal\n");
        else if (ans >= INF)
            printf("INF\n");
        else printf("%I64d\n", ans);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值