題目背景
陰天傍晚車窗外
未來有一個人在等待
向左向右向前看
愛要拐幾個彎才來
我遇見誰會有怎樣的對白
我等的人他在多遠(yuǎn)的未來
我聽見風(fēng)來自地鐵和人海
我排著隊拿著愛的號碼牌
題目描述
城市中人們總是拿著號碼牌,不停尋找,不斷匹配,可是誰也不知道自己等的那個人是誰。
可是燕姿不一樣,燕姿知道自己等的人是誰,因為燕姿數(shù)學(xué)學(xué)得好!燕姿發(fā)現(xiàn)了一個神奇的算法:假設(shè)自己的號碼牌上寫著數(shù)字 S,那么自己等的人手上的號碼牌數(shù)字的所有正約數(shù)之和必定等于 S。
所以燕姿總是拿著號碼牌在地鐵和人海找數(shù)字(喂!這樣真的靠譜嗎)可是她忙著唱《綠光》,想拜托你寫一個程序能夠快速地找到所有自己等的人。
輸入輸出格式
輸入格式:
輸入包含 k 組數(shù)據(jù)。 對于每組數(shù)據(jù),輸入包含一個號碼牌S。
輸出格式:
對于每組數(shù)據(jù),輸出有兩行,第一行包含一個整數(shù) m,表示有 m 個等的人。
第二行包含相應(yīng)的 m 個數(shù),表示所有等的人的號碼牌。
注意:你輸出的號碼牌必須按照升序排列。
一個正整數(shù)n可以被分成p1a1*p2a2p3^a3pn^an;
piai的正約數(shù)個數(shù)為ai+1,即1,pi1,pi2,pi3,....,pi^ai,所以n的正約數(shù)個數(shù)為(a1+1)(a2+1)(a3+1)...(an+1);
實(shí)際上n的約數(shù)是在p1a1、p2a2、...、pk^ak每一個的約數(shù)中分別挑一個相乘得來,
可知共有(a?+1)(a?+1)(a?+1)…(ak+1)種挑法,即約數(shù)的個數(shù)。
由[乘法原理]可知它們的和為
f(n)=(p10+p11+p12+…p1a1)(p20+p21+p22+…p2a2)…(pk0+pk1+pk2+…pkak)
于是乎就有了搜索策略,搜索p,并枚舉他的冪次,滿足一下兩個條件即為滿足解
①最后分解完,剩余得1,將所得結(jié)果記錄②分解剩余的數(shù)-1是一個質(zhì)數(shù)p,這樣就可以看成p0+p1,也可以得到結(jié)果,將其記錄
代碼如下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define LL long long
#include<algorithm>
using namespace std;
int prime[50010],vis[50010],cnt,ans[100010],cnt1;
LL s;
void GetPrime(){
memset(vis,1,sizeof(vis));
for(int i=2;i<=50000;i++){
if(!vis[i]) continue;
prime[++cnt]=i;
for(int j=2;j<=50000/i;j++) vis[i*j]=0;
}
}
int check_prime(LL x){
if(x<=50000&&vis[x]==0) return 0;
for(int i=1;prime[i]*prime[i]<=x;i++) if(x%prime[i]==0) return 0;
return 1;
}
void dfs(LL now,int last,LL left){
if(left==1){//情況1
ans[++cnt1]=now;
return;
}
if(left-1>prime[last]&&check_prime(left-1)) ans[++cnt1]=now*(left-1);//情況2
for(int i=last+1;prime[i]*prime[i]<=left;i++)
for(LL temp=prime[i]+1,t=prime[i];temp<=left;t*=prime[i],temp+=t) if(left%temp==0) dfs(now*t,i,left/temp);
}
int main(){
GetPrime();
while(scanf("%lld",&s)!=EOF){
cnt1=0;
dfs(1,0,s);
sort(ans+1,ans+cnt1+1);
printf("%d\n",cnt1);
for(int i=1;i<=cnt1;i++){
if(i==cnt1) printf("%d\n",ans[i]);
else printf("%d ",ans[i]);
}
}
return 0;
}