【JLOI2014】聪明的燕姿(数论)

首先有个结论:

如果一个数N可以分解为:

N=p_1^{c_1}*p_2^{c_2}*...*p_k^{c_k},其中p为素数,c表示次数。

那么N的所有正因数之和为:

S=(1+p_1+p_1^2+...+p_1^{c_1})*...*(1+p_k+p_k^2+...+p_k^{c_k})

对于此题用深搜,枚举p是无法避免的,且p可能为S-1,甚至无法打素数表。但我们可以枚举较小的素数,然后特判另一部分是否是一个质数,可以证明这样不会重复统计答案,因为即使S的分解一样,但分到N的因数上就不一样了。

于是我们搜索,可以只枚举那些小于等于根号S的质数,直到能够整除当前值,然后进入下一层搜索。当前值等于1时得到一个答案,或者当前值-1是一个质数也得到一个答案。

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN=50000;
int N,vis[MAXN+5],tot=0,cnt=0,ans[100000],prime[MAXN+5];

void get_prime()
{
	for(int i=2;i<=MAXN;i++)
	{
		if(!vis[i]) prime[++tot]=i;
		for(int j=1;j<=tot&&prime[j]*i<=MAXN;j++)
		{
			vis[prime[j]*i]=1;
			if(i%prime[j]==0) break;
		}
	}
	vis[1]=1;
}

int is_prime(LL x)
{
	if(x<=MAXN) return 1-vis[x];
	
	for(LL i=2;i*i<=x;i++)
		if(x%i==0) return 0;
		
	return 1;
}

void dfs(LL now,int x,LL t)
{
	if(now==1)
	{
		ans[++cnt]=t;
		return;
	}
	
	if(now-1>=prime[x]&&is_prime(now-1))
		ans[++cnt]=(now-1)*t;
		
	int i;
	LL j,tmp;
	for(i=x;i<=tot&&prime[i]*prime[i]<=now;i++)
	{
		j=prime[i]+1;
		tmp=prime[i];
		for(;j<=now;tmp*=prime[i],j+=tmp)
			if(now%j==0) dfs(now/j,i+1,t*tmp);
	}
}

int main()
{
	LL S; get_prime();
	while(scanf("%lld",&S)==1)
	{
		cnt=0;
		dfs(S,1,1ll);
		sort(ans+1,ans+1+cnt);
		printf("%d\n",cnt);
		for(int i=1;i<=cnt;i++) printf("%d ",ans[i]);
		if(cnt) printf("\n");
	}
	return 0;
}

 

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值