bzoj3629: [JLOI2014]聪明的燕姿
Description
阴天傍晚车窗外
未来有一个人在等待
向左向右向前看
爱要拐几个弯才来
我遇见谁会有怎样的对白
我等的人他在多远的未来
我听见风来自地铁和人海
我排着队拿着爱的号码牌
城市中人们总是拿着号码牌,不停寻找,不断匹配,可是谁也不知道自己等的那个人是谁。可是燕姿不一样,燕姿知道自己等的人是谁,因为燕姿数学学得好!燕姿发现了一个神奇的算法:假设自己的号码牌上写着数字S,那么自己等的人手上的号码牌数字的所有正约数之和必定等于S。
所以燕姿总是拿着号码牌在地铁和人海找数字(喂!这样真的靠谱吗)可是她忙着唱《绿光》,想拜托你写一个程序能够快速地找到所有自己等的人。
Input
输入包含k组数据(k<=100)对于每组数据,输入包含一个号码牌S
Output
对于每组数据,输出有两行,第一行包含一个整数m,表示有m个等的人,第二行包含相应的m个数,表示所有等的人的号码牌。注意:你输出的号码牌必须按照升序排列。
Sample Input
42
Sample Output
3
20 26 41
HINT
对于100%的数据,有S<=2*10^9
题解
根据算数基本定理,每个数都可以唯一分解成有限的质数的积的形式。
根据约数和公式,一个数的约数和等于每个质因数升幂和的乘积。
这样我们就可以枚举质数以及它的指数,进行搜索。
代码
/*
The violence is miraculous and the standard procedure is defeated.
*/
#include<bits/stdc++.h>
#define MAXN 100010
using namespace std;
int p[MAXN],cnt,T,S;
vector<int> ans;
bool np[MAXN];
inline bool Check(int x){
if(x<=100000)return np[x]? 0:1;
for(int i=1;p[i]*p[i]<=x&&i<=cnt;i++)if(x%p[i]==0)return 0;
return 1;
}
void DFS(int now){//Processing the No.now prime number
if(S==1){ans.push_back(T);return;}
if(S-1>p[now-1]&&Check(S-1))ans.push_back(T*(S-1));
for(int i=now;p[i]*p[i]<=S;i++){
for(int j=p[i]+1,k=p[i];j<=S;k*=p[i],j+=k){
if(S%j==0){S/=j;T*=k;DFS(i+1);S*=j;T/=k;}
}
}
}
int main(){
freopen("swallow.in","r",stdin);
freopen("swallow.out","w",stdout);
np[1]=1;
for(int i=2;i<=100000;i++){
if(!np[i])p[++cnt]=i;
for(int j=1;j<=cnt;j++){
int t=i*p[j];
if(t>100000)break;
np[t]=1;
if(i%p[j]==0)break;
}
}
while(scanf("%d",&S)==1){
ans.clear();T=1;
DFS(1);
int siz=ans.size();
printf("%d\n",siz);
sort(ans.begin(),ans.end());
for(int i=0;i<siz;i++)printf("%d%c",ans[i],i==siz-1? '\n':' ');
}
return 0;
}