JLOI2014 聪明的燕姿【搜索-细节】

题目链接

题目解析

两个公式:

整数唯一分解定理:

(n=prod_{i=1}^mp_i^{α_i})

约数和定理:

(S=prod_{i=1}^msum_{j=0}^{α_i}p_i^j)

然后可以搜索质因子和它们的指数,记录下当前还剩多少和(s),已经枚举到的第(i)个质数,目前产生的答案(x)

需要剪枝:若(p^2>=S),有(frac{s}{p+1}<p),而我们又是递增枚举这个(p)的,所以后面就不用枚举了,这个一定不合法(那么所提到的这个答案在(frac{s}{p+1})就已经算过了(因为从小到大))

除非它是最后一个,后面没有数,也就是(p+1==s),那么这种情况可以特判:

如果(s-1)是质数,并且比上一次枚举到的质因子大,那么就把((s-1) imes x)也算入答案。

这道题输出调了我好久(见注释,果然是太菜了嘛(qwq)

虽然我没有燕姿那么聪明,但是希望我也能找到自己等的人叭,不需要所有,有就够了。


►Code View

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
#define N 100005
#define INF 0x3f3f3f3f
int rd()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return f*x;
}
int prim[N],pn;
bool vis[N];
int ans[N],cnt;
void Sieve()
{
	for(int i=2;i<N;i++)
	{
		if(!vis[i]) prim[++pn]=i;
		for(int j=1;j<=pn&&prim[j]*i<N;j++)
		{
			vis[i*prim[j]]=1;
			if(i%prim[j]==0) break;
		}
	}
}
bool check(int x)
{
	if(x==1) return 0;
	for(int i=1;prim[i]*prim[i]<=x;i++)
		if(x%prim[i]==0) return 0;
	return 1;
}
void dfs(int now,int i,int x)
{//还剩多少没有分解 第几个质数 当前答案 
	if(now==1)
	{
		ans[++cnt]=x;
		return ;
	}
	if(check(now-1)&&now-1>prim[i]) ans[++cnt]=(now-1)*x;//sum-1是满足条件的一个质因子
	for(int j=i+1;prim[j]*prim[j]<=now;j++)
	{//枚举质因子 
		int sum=1+prim[j],lst=prim[j];
		while(sum<=now)
		{
			if(now%sum==0) dfs(now/sum,j,x*lst);
			lst*=prim[j],sum+=lst;
		}
	}
}
int main()
{
	Sieve();
	int s;
	while(scanf("%d",&s)!=EOF)
	{
		cnt=0;
		dfs(s,0,1);
		sort(ans+1,ans+cnt+1);
		printf("%d
",cnt);
		for(int i=1;i<=cnt;i++)
			printf("%d ",ans[i]);
		if(cnt) puts("");//Cao 注意格式啊 如果没有数 那么就没有这个换行 也不能这么打(见下 
		/*
		for(int i=1;i<cnt;i++)
			printf("%d ",ans[i]);
		printf("%d
,ans[cnt]);
		因为不知道cnt有没有 如果cnt==0 就会多输出一个ans[0]啊 
		*/ 
	} 
	return 0;
} 
原文地址:https://www.cnblogs.com/lyttt/p/14004843.html