解析:
首先,我们需要知道一个约数和公式。
对于 n = ∏ i = 1 t p i k i n= \prod_{i=1}^{t}p_i^{k_i} n=∏i=1tpiki, n n n的约数之和(包括 n n n和1)为 ∏ i = 1 t ∑ j = 0 k i p i j \prod_{i=1}^{t}\sum_{j=0}^{k_i}p_i^{j} ∏i=1t∑j=0kipij,
所以我们要求的就是所有合法的 n n n,使得其约数之和 s s s.
搜索,由于 ∑ j = 0 k i p i j \sum_{j=0}^{k_i}p_i^{j} ∑j=0kipij这一项的增长是指数级的,所以时间复杂度实际上非常小。具体实现看代码。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
int getint(int &num){
num=0;
re char c=gc();
while(!isdigit(c)&&(~c))c=gc();
if(c==EOF)return EOF;
while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
return 1;
}
inline
void outint(int a){
st char ch[13];
if(a==0)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
bool mark[100000];
int prime[100000],pcnt;
inline
void linear_sieves(int len=100000){
mark[1]=true;
for(int re i=2;i<=len;++i){
if(!mark[i])prime[++pcnt]=i;
for(int re j=1;i*prime[j]<=len;++j){
mark[i*prime[j]]=true;
if(i==i/prime[j]*prime[j])break;
}
}
}
inline
bool isprime(int n){
if(n<=100000)return !mark[n];
for(int re i=1;prime[i]*prime[i]<=n;++i)if(n==n/prime[i]*prime[i])return false;
return true;
}
int ans[1000000],tot;
inline
void dfs(int lastpos,int total,int now){
if(total==1)return (void)(ans[++tot]=now);
if(total-1>prime[lastpos]&&isprime(total-1)){
ans[++tot]=now*(total-1);
}
for(int re i=lastpos+1;prime[i]*prime[i]<=total;++i){
ll res=1,tmp=prime[i];
while(res+tmp<=total){
res+=tmp;
if(total==total/res*res)
dfs(i,total/res,now*tmp);
tmp*=prime[i];
}
if(res==1)break;
}
}
int n;
int main(){
linear_sieves();
while(~getint(n)){
tot=0;
dfs(0,n,1);
sort(ans+1,ans+tot+1);
outint(tot),pc('\n');
for(int re i=1;i<=tot;++i)outint(ans[i]),
pc(i==tot?'\n':' ');//不这样写本校OJ居然说我输出过长
}
return 0;
}