zoj2562 More Divisors && CF27E. Number With The Given Amount Of Divisors(反素数)


http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1562

题意:求n以内因子最多的那个数。


思路:范围非常大,不能用普通的求约数个数方法。反素数,就是小于这个数的所有数因子都没他多,那么就转变成求1~n之间的最大反素数。

反素数的写法,自己没想出来,看的这位大佬这位


除此之外,还有一个重要性质:

(3)对于p = 2^t1*3^t2*5^t3*7^t4....,p的因子的个数为(t1+1)*(t2+1)*...*(tn+1)。

根据性质(2)(3),总因子个数转化为求每个因子幂个数的组合,通过对可能的幂的个数穷举来达到模拟所有结果。要想使因子最多,2、3等靠前面的素数的因子肯定较多,越往后越少,然而说是这么说的,少也不代表没有,至少这题说明了要事先准备前16个素数才够(可能要少些,我也懒得去试了),至于是不是和10^16有联系,我不知道怎么算出来的= =。枚举的素数个数上限之所以是54,是因为假如最多全是2的幂,一共要2^54才能满足比10^16大的条件。为了满足条件2,每次dfs的幂上限都是上一层的幂大小。这样就转变成最大54叉的,越往下叉越小的一颗树。


感觉每次描述dfs都相当抽象,咋就自己写不出来呢T T。。


#include <stdio.h>
#include <algorithm>
#include <string.h>

using namespace std;

typedef long long ll;
const int N = 5010;
const int INF = 0x3f3f3f3f;

int prime[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};

ll Maxcur, Maxcnt, n;//Maxcur代表最大因子个数对应的反素数,Maxcnt代表最大因子个数

void dfs(ll step, ll cur, ll cnt, ll Maxnum)
{
    if(step >= 16) return;
    if(cnt > Maxcnt)
    {
        Maxcur = cur;
        Maxcnt = cnt;
    }
    if(cnt==Maxcnt && cur<Maxcur) Maxcur = cur;
    ll tmp = cur;//在原先反素数的基础上乘第step个素数
    for(int i = 1; i <= Maxnum; i++)//枚举第step个素数的个数
    {
        tmp*=prime[step];
        if(tmp>n) return;
        dfs(step+1, tmp, cnt*(i+1), i);//下一个质因子肯定个数要比这个少
    }
}

int main()
{
   // freopen("in.txt", "r", stdin);
    while(~scanf("%lld", &n))
    {
        dfs(0, 1, 1, 54);
        printf("%lld\n", Maxcur);
    }
    return 0;
}


http://codeforces.com/problemset/problem/27/E

题意:给一个数n,求一个最小正整数,使得它的因子个数为n。


思路:反素数的问题一般有两类,一类是给定n,求最大因子数;另一类是给定因子n,求最小数。本题属于后一类。思路写注释了。

codeforce没打过,注册好麻烦,这题没提交,只是搞出个得数。。


#include <stdio.h>
#include <algorithm>
#include <string.h>

using namespace std;

typedef long long ll;
const int N = 5010;
const int INF = 0x3f3f3f3f;

int prime[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};

ll ans, n;//ans表示满足约数为n的反素数,通过多次贪心求的最小值

void dfs(ll step, ll cur, ll cnt, ll Maxnum)//cur表示当前因子个数所对应的反素数,cnt表示当前因子个数
{
    if(step >= 16) return;
    if(cnt==n && cur<ans) ans = cur;//更新最小反素数
    ll tmp = cur;//在原先反素数的基础上乘第step个素数
    for(int i = 1; i <= Maxnum; i++)//枚举第step个素数的个数
    {
        tmp*=prime[step];
        if(tmp>ans) return;//若乘上这个质因子超过了已知最大反素数,不满足求最小反素数的条件,返回
        dfs(step+1, tmp, cnt*(i+1), i);//下一个质因子肯定个数要比这个少,因子个数累乘
    }
}

int main()
{
   // freopen("in.txt", "r", stdin);
    while(~scanf("%lld", &n))
    {
        ans = INF;
        dfs(0, 1, 1, 63);
        printf("%lld\n", ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值