1629:聪明的燕姿

1629:聪明的燕姿


时间限制: 1000 ms         内存限制: 524288 KB
提交数: 103     通过数: 53

【题目描述】

城市中人们总是拿着号码牌,不停寻找,不断匹配,可是谁也不知道自己等的那个人是谁。

可是燕姿不一样,燕姿知道自己等的人是谁,因为燕姿数学学得好!燕姿发现了一个神奇的算法:假设自己的号码牌上写着数字 S

,那么自己等的人手上的号码牌数字的所有正约数之和必定等于 S

所以燕姿总是拿着号码牌在地铁和人海找数字(喂!这样真的靠谱吗)可是她忙着唱《绿光》,想拜托你写一个程序能够快速地找到所有自己等的人。

【输入】

输入包含 k

组数据。

对于每组数据,输入包含一个号码牌S

【输出】

对于每组数据,输出有两行,第一行包含一个整数 m

,表示有 m

个等的人。

第二行包含相应的 m

个数,表示所有等的人的号码牌。

注意:你输出的号码牌必须按照升序排列。

【输入样例】

42

【输出样例】

3
20 26 41

【提示】

数据范围与提示

对于 100% 的数据,k100, S2×109

其实这道题一点都不难

解答本题的关键在于对唯一分解定理和约数和公式的理解。分解数即可

代码中left表示被剩下的未被分解的数,sum'表示当前得到的结果,pos表示检索第几个质数。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+1;
bool mark[N];
int prime[N],tot,ans[N],S;
inline void Pre()
{
    int i,j,cnt=0;
    for(i=2;i<=N;i++)
    {
        if(!mark[i]) 
        {
            mark[i]=1;
            prime[++cnt]=i;
        }
        for(int j=1;j<=cnt&&prime[j]<=N/i;j++)
        {
            mark[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
    //for(int i=1;i<=100;i++)
    //printf("%d ",prime[i]);
}
inline bool judge(int x)
{
    for(int i=2;i<=sqrt(x);i++)
    if(x%i==0) return false;
    return true;
}
void dfs(int pos,int sum,int left)
{
    if(left==1)
    {
        ans[++tot]=sum;
        return ;
    }
    if(judge(left-1)&&left>prime[pos]) 
    {
        ans[++tot]=sum*(left-1);
    }
    for(int i=pos;prime[i]*prime[i]<=left;i++)
    {
        int Sum=prime[i]+1,tmp=prime[i];
        for(;Sum<=left;tmp*=prime[i],Sum+=tmp)
        {
            if(left%Sum==0)
            dfs(i+1,sum*tmp,left/Sum);
        }
    }
}
signed main()
{
    Pre();
    while(~scanf("%lld",&S))
    {
        tot=0;
        dfs(1,1,S);
        sort(ans+1,ans+tot+1);
        printf("%lld
",tot);
        for(int i=1;i<=tot;i++)
        printf("%lld ",ans[i]);
        if(tot) puts("");
    }
    return 0;
}

最后,值得注意的是这道题的输出有坑,得自己去WA下试试才知道

原文地址:https://www.cnblogs.com/smartljy/p/11394449.html