看那么多人给燕姿打call,那就默默+1
题里说的很清楚,约数和等于s的数是答案
先普及一些东西
一个数可以分解为P1^a1*P2^a2*.......*Pn^an,其中P1~Pn都是素数,(算术基本定理:任何一个大于 1 的自然数(不为素数)可以分解成一些素数的乘积;并且在不计次序的情况下,这种分解方式是唯一的。),这个定理,我们可以说是显然的,我们从2开始,如果他MOD2==0,说明可以被2整除,那就把它除以2^n,直到不能被2整除,那这时,2的所有倍数都不能被当前数整除,(抹掉了一大片合数),然后是3,同2,3的倍数也都是合数,此时他们也不能被当前数整除,然后4,4是2的倍数,不能被整除,然后是5,以此类推,之后便可以发现当前数被分成了若干个质数的幂次方的乘积,存在性可以运用反证法证明,若当前数被分解完后,存在一个合数的幂次方,假设这个合数的两个因子为q和p,那么如果他们都是合数,那么又可以这么分下去,直到分成若干个素数相乘,那么当前数又变成了素数的乘积。
然后是 约数个数定理
由上面的数的分解可以看出一个显然的事情:P1^0,P1^1,P1^2.......P1^a1都是当前数的约数,共(a1+1)个,那么同理,由乘法原理可得,当前数的约数共(a1+1)*(a2+1)*.......*(an+1)个。
约数和定理
令n的正约数和为f(n)
可知p1^a1的约数有:p1^0, p1^1, p1^2......p1^a1
同理可知,pk^ak的约数有:pk^0, pk^1, pk^2......pk^ak ;
n的约数是在p1^a1、p2^a2、...、pk^ak可以看为每一个的约数中分别挑一个相乘得来,
可知共有(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)
之后我们可以发现,从每个小括号里取出一项,一个小惊喜,乘起来后,又变成了一个数的分解形式,并且,你会发现这个递归数的约数和(f(n)),就是你的单个括号内所有数之和 。
另外,还有一点,如果当前数-1是一个素数,那么当前数-1也是一组可行解,为什么呢,当前数-1是素数,那么他的约数只有他和1,那么约数和就是他+1,就是原数
欧拉线性筛
一开始时要预处理出所有素数,但是2*10^9,有点大,所以要将素数存入数组中
欧拉线性筛保证每个合数被他的最小质因子删掉了,并且只删了一次,所以,复杂度为o(n);
好了,下面给出上面涉及到的涉及到约束的定理以及AC代码(分解为P1^a1形式就把第一个代码变成k++,然后输出^k)
update 18-09-03
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=105000;
int n;
int num[M],pri[M],vis[M],tot=0,cnt=0;
inline void getpri()
{
pri[0]=pri[1]=1;
for (int i=2;i<M;i++)
{
if (!vis[i]) pri[++tot]=i;
for (int k=1;k<=tot&&pri[k]*i<M;k++)
{
vis[pri[k]*i]=1;
if (i%pri[k]==0) break;
}
}
return ;
}
inline bool che(int x)
{
if (x<2) return 0;
for (int i=1;pri[i]<=sqrt(x);i++)
if (x%pri[i]==0) return 0;
return 1;
}
inline void dfs(int x,int pr,int la)
{
if (x==1) return (void)(num[++cnt]=pr);
if (x-1>=pri[la]&&che(x-1)) num[++cnt]=(x-1)*pr;
for (int i=la;pri[i]<=sqrt(x);i++)
{
int npr=pri[i];
for (int k=pri[i]+1;k<=x;k+=npr)
{
if (x%k==0) dfs(x/k,npr*pr,i+1);
npr*=pri[i];
}
}
return ;
}
signed main()
{
getpri();
while (~scanf("%d",&n)&&n)
{
fill(num,num+cnt+1,0);
cnt=0;dfs(n,1,1);printf("%d\n",cnt);
if (!cnt) continue;sort(num+1,num+cnt+1);
for (int i=1;i<=cnt;i++) printf("%d ",num[i]);
puts("");
}
return 0;
}