聪明的燕姿

题目描述

在这里插入图片描述

分析

提到约数之和,就不难想到约数个数和约数之和的两个公式
在这里插入图片描述
对于这道题来说,如果这个数大于S,那么这个数必然有两个因子,一个1一个S,那么这个数一定不符合要求,因此只需要在1~S中考虑即可

假设X分解出的每一个素因子都是230=1 073 741 824,因此每个素因子的次幂都不会太多
假设X分解出的每个素因子都只出现1次,且出现的都是最小的,仅仅考虑前15个素数求素数和的答案是1 610 612 736,每个因子分解出来的素数不会太多
两者结合起来,X分解出来的素因子和次幂数就更不会很大了!
因此可以直接暴搜,搜出所有的素因子和次幂就可以啦

首先规定搜索的顺序,默认枚举的素因子是严格单调递增的
如果我们要直接枚举所有可能的质数的话,就需要枚举大概1e8左右的数,很显然这是不行的,需要想一些剪枝来优化搜索的过程
对于每一个当前剩余的S,都判断S是否等于a(质数)+1
如果满足,则不用再进行下面的枚举
如果不满足,则有一下两种情况
在这里插入图片描述
不论是对于哪一种情况,都必然会有pi2<S,因此我们只需要枚举到S1/2即可,这样复杂度就大大降低了

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 45000;
int prime[N], cnt;
bool st[N];
int ans[N], len;
void get_prime(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
            prime[cnt++] = i;
        for (int j = 0; prime[j] * i <= n; j++)
        {
            st[prime[j] * i] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}
bool check(int n)
{
    if (n < N)
        return !st[n];
    for (int i = 0; prime[i] <= n / prime[i]; i++)
        if (n % prime[i] == 0)
            return 0;
    return 1;
}
//last表示当前用到的素数的下标是多少
//res表示当前的答案是多少
//s表示当前剩余的S是多少
void dfs(int last, int res, int s)
{
    if (s == 1) //表示这个数已经被完美的凑出来了
    {
        ans[len++] = res;
        return;
    }
    if (s - 1 > (last < 0 ? 1 : prime[last]) && check(s - 1))
        ans[len++] = res * (s - 1);
    for (int i = last + 1; prime[i] <= s / prime[i]; i++)
    {
        int temp = prime[i];
        for (int j = 1 + temp, t = temp; j <= s; t *= temp, j += t) //j保存的是和,t保存的是最后一个次幂的值
            if (s % j == 0)
                dfs(i, res * t, s / j);
    }
}
int main()
{
    get_prime(N - 1);
    int s;
    while (cin >> s)
    {
        len = 0;
        dfs(-1, 1, s);
        cout << len << endl;
        if (len)
        {
            sort(ans, ans + len);
            for (int i = 0; i < len; i++)
                cout << ans[i] << " ";
            cout << endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值