【JSOI 2014】聪明的燕姿

传送门

【题目背景】

阴天傍晚车窗外
未来有一个人在等待
向左向右向前看
爱要拐几个弯才来
我遇见谁会有怎样的对白
我等的人他在多远的未来
我听见风来自地铁和人海
我排着队拿着爱的号码牌

【题目描述】

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

可是燕姿不一样,燕姿知道自己等的人是谁,因为燕姿数学学得好!燕姿发现了一个神奇的算法:假设自己的号码牌上写着数字 S,那么自己等的人手上的号码牌数字的所有正约数之和必定等于 S。

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

输入格式:

输入包含\(k\)组数据。对于每组数据,输入包含一个号码牌\(S\)

输出格式:

对于每组数据,输出有两行,第一行包含一个整数\(m\),表示有\(m\)个等的人。
第二行包含相应的\(m\)个数,表示所有等的人的号码牌。
注意:你输出的号码牌必须按照升序排列。

【Input】

42

【Output】

3
20 26 41

【分析】

看了不少大佬的题解,这里写一下蒟蒻自己的理解,至于代码,其实和各位大佬的差不多。
首先,这里要用到惟一分解定理:
\[n=p_1^{c_1}*p_2^{c_2}*……*p_k^{c_k}\]
还有约数和:
\[sum=\prod_{i=1}^{n}{\sum_{j=0}^{k}{p_i^j}}\]
这些应该没什么好说的。注意,如果\(s-1\)为质数,则\(s-1\)也是一个号码牌,所以这里需要特判。搜索中的\(now\)相当于搜寻到的质数的乘积,\(last\)为搜索的质数的下标,\(left\)为剩下的\(s\)

【代码】

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define maxn 60000
using namespace std;
int s;
int cnt=0,num;
int prime[maxn],ans[maxn];
bool flag[maxn];
void primes(){
    memset(flag,1,sizeof(flag));//筛素数
    flag[1]=0;
    for(int i=2;i<=maxn;i++){
        if(!flag[i]) continue;
        else{
            prime[++cnt]=i;
            for(int j=2;j*i<=maxn;j++)
                flag[i*j]=0;
        }
    }
}
bool is_prime(int x){//判断是否为素数
    if(x==1) return false;
    if(x==2) return true;
    for(int i=1;prime[i]*prime[i]<=x;i++)
        if(x%prime[i]==0) return false;
    return true;
}
void dfs(int now,int last,int left){//搜索
    if(left==1) {ans[++num]=now;return;}
    if(left-1>prime[last]&&is_prime(left-1)) ans[++num]=now*(left-1);
    for(int i=last+1;prime[i]*prime[i]<=left;i++)
        for(int j=prime[i]+1,k=prime[i];j<=left;k*=prime[i],j+=k)
            if(left%j==0)
                dfs(now*k,i,left/j);
}
int main(){
    primes();
    while(scanf("%d",&s)!=EOF){
        num=0;
        memset(ans,0,sizeof(ans));
        dfs(1,0,s);
        sort(ans+1,ans+1+num);//号码牌要按升序排列
        printf("%d\n",num);
        for(int i=1;i<=num;i++){
            printf("%d",ans[i]);
            if(i==num) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hlw1/p/11104874.html