JLOI2014 聪明的燕姿【搜索-细节】
题目解析
两个公式:
整数唯一分解定理:
\(n=\prod_{i=1}^mp_i^{α_i}\)
约数和定理:
\(S=\prod_{i=1}^m\sum_{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)\times 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\n",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\n,ans[cnt]);
因为不知道cnt有没有 如果cnt==0 就会多输出一个ans[0]啊
*/
}
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com