题意
求约数个数和为 n n 的数有哪几个
题解
首先我们来看一个定理:约数和定理(下文会用到)
对于任意一个大于1的正整数N可以分解正整数: ,则由约数个数定理可知 x x 的正约数有 个,那么 x x 的 个正约数的和为 f(x)=(P01+P11+P21+…Pa11)(P02+P12+P22+…Pa22)…(P0n+P1n+P2n+…Pann) f ( x ) = ( P 1 0 + P 1 1 + P 1 2 + … P 1 a 1 ) ( P 2 0 + P 2 1 + P 2 2 + … P 2 a 2 ) … ( P n 0 + P n 1 + P n 2 + … P n a n )
因此递归搜索解决,枚举 pi p i ,再对应枚举 ai a i
约数的和为 n n ,即 ,所以 x<n x < n (否则都会至少大于等于 n+1 n + 1 )
然后就可以愉快的深搜了
如果此时刚好可以表示成 一个质数+1,那么结果就会有 当前的结果 * 质数
然后对于每个未搜索过的质数,枚举
ai
a
i
再去深搜就可以了
代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;
#define ll long long
#define N 100010
ll n,ans[N],phi[N],s1[N];
int num=0,tot,notprime[N],prime[N];
inline void getprime(){
notprime[1]=1;
for(int i=2;i<=100000;i++){
if(!notprime[i]) prime[++tot]=i;
for(int j=1;j<=tot && prime[j]*i<=100000;j++){
notprime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
inline bool isprime(ll x){
if(x<=100000) return !notprime[x];
for(int i=1;i<=tot;i++) if(x%prime[i]==0) return 0;
return 1;
}
void dfs(int last,ll now,ll s){ //解决约数个数和为 s 的问题
if(s==1){ans[++num]=now;return;}
if(s-1>prime[last] && isprime(s-1))
ans[++num]=now*(s-1);
for(int i=last+1;prime[i]*prime[i]<=s;i++){
for(int tnum=prime[i]+1,t=prime[i];tnum<=s;t*=prime[i],tnum+=t){
if(s%tnum==0)
dfs(i,now*t,s/tnum);
}
}
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
getprime();
while(scanf("%lld",&n)>0){
num=0;dfs(0,1,n);
printf("%d\n",num);
sort(ans+1,ans+num+1);
for(int i=1;i<=num;i++) printf("%lld%c",ans[i],i==num?'\n':' ');
}
return 0;
}