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
题解
对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个,
那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
由此可见,这题就是一个搜索题
可怎么搜索呢?
穷举Pi及其对应的ai进行搜索。
- 若当前数可表示成一个并未搜索过的质数与1的和,则之前搜索过的数与这个质数的乘积符合题意。
- 对于每一个未被搜索过且平方小于当前数的质数,则枚举所有可能符合题意的ai进行递归搜索。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
#define N 50000
int s,sqrts,top,cnt;
int p[N+10],ans[N * 2];
bool vis[N+10];
void getpri()
{
memset(vis,1,sizeof(vis));
vis[1] = 0;
for(int i = 2;i <= N;i++)
{
if(vis[i]) p[++cnt] = i;
for(int j = 1;p[j] * i <= N;j++)
{
vis[p[j] * i] = 0;
if(i % p[j] == 0) break;
}
}
}
bool jud(int x)
{
if(x <= N) return vis[x];
else
{
int t = sqrt(x);
for(int i = 1;p[i] <= t;i++)
if(x % p[i] == 0) return 0;
return 1;
}
}
void dfs(int last,ll tot,int sum)
{
if(tot == 1){ans[++top] = sum;return;}
if(tot - 1 > sqrts && jud(tot-1)) ans[++top] = sum*(tot-1);
for(int i = last+1;p[i] <= sqrts;i++)
{
ll tmp = 1,t = p[i];
for(int j = 1;tmp + t <= tot;j++)
{
tmp += t;
if(tot % tmp == 0) dfs(i,tot/tmp,sum*t);
t *= p[i];
}
}
}
int main()
{
getpri();
while(scanf("%d",&s) != EOF)
{
top = 0; sqrts = sqrt(s);
dfs(0,s,1);
printf("%d\n",top);
sort(ans+1,ans+top+1);
for(int i = 1;i < top;i++)
printf("%d ",ans[i]);
if(top) printf("%d\n",ans[top]);
}
return 0;
}