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
",siz);
		sort(ans.begin(),ans.end());
		for(int i=0;i<siz;i++)printf("%d%c",ans[i],i==siz-1? '
':' ');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lrj998244353/p/8809236.html