「BZOJ3629」[JLOI2014] 聪明的燕姿
Description
阴天傍晚车窗外
未来有一个人在等待
向左向右向前看
爱要拐几个弯才来
我遇见谁会有怎样的对白
我等的人他在多远的未来
我听见风来自地铁和人海
我排着队拿着爱的号码牌
城市中人们总是拿着号码牌,不停寻找,不断匹配,可是谁也不知道自己等的那个人是谁。可是燕姿不一样,燕姿知道自己等的人是谁,因为燕姿数学学得好!燕姿发现了一个神奇的算法:假设自己的号码牌上写着数字S,那么自己等的人手上的号码牌数字的所有正约数之和必定等于S。
所以燕姿总是拿着号码牌在地铁和人海找数字(喂!这样真的靠谱吗)可是她忙着唱《绿光》,想拜托你写一个程序能够快速地找到所有自己等的人。
Input
输入包含k组数据(k<=100)
对于每组数据,输入包含一个号码牌S
Output
对于每组数据,输出有两行,第一行包含一个整数m,表示有m个等的人,第二行包含相应的m个数,表示所有等的人的号码牌。注意:你输出的号码牌必须按照升序排列。
Sample Input
42
Sample Output
3
20 26 41
20 26 41
HINT
对于100%的数据,有S<=2*109
题解
我们一起膜拜wulala吧
http://wulala.logdown.com/posts/207881-stefanie-jloi-2014-smart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> #include<cstring> #define ll long long using namespace std; int s,sqrts,top,cnt; int ans[100000],p[50005]; bool mark[50005]; void getpri() { for(int i=2;i<=50000;i++) { if(!mark[i])p[++cnt]=i; for(int j=1;p[j]*i<=50000;j++) { mark[p[j]*i]=1; if(i%p[j]==0)break; } } } bool jud(int x) { if(x<=50000)return (!mark[x]); else { int t=sqrt(x); for(int i=1;p[i]<=t;i++) if(x%p[i]==0)return 0; return 1; } } void dfs(int last,ll tot,int sum) { if(tot==1){ans[++top]=sum;return;} if(tot-1>sqrts&&jud(tot-1))ans[++top]=sum*(tot-1); for(int i=last+1;p[i]<=sqrts;i++) { ll tmp=1,t=p[i]; for(int j=1;tmp+t<=tot;j++) { tmp+=t; if(tot%tmp==0) dfs(i,tot/tmp,sum*t); t*=p[i]; } } } int main() { getpri(); while(scanf("%d",&s)!=EOF) { top=0;sqrts=sqrt(s); dfs(0,s,1); printf("%d\n",top); sort(ans+1,ans+top+1); for(int i=1;i<top;i++) printf("%d ",ans[i]); if(top)printf("%d\n",ans[top]); } return 0; } |
倒着枚举质数出奇迹 ORZ %%%