找伙伴
找伙伴(数论 \(\star\star \))
- 时限:\(1s\) 内存:\(256M\)
Descrption
- 在班级里,每个人都想找学习伙伴。伙伴不能随便找,都是老师固定好的,老师给出要求:伙伴要凭自己实力去找。
- 老师给每个人发一张纸,上面有数字。假设你的数字是 \(w\),那么如果某位同学手中的数字的所有正约数之和等于 \(w\),那么这位同学就是你的小伙伴。
Input
- 输入包含n组数据(最多 \(100\) 组)
- 对于每组测试数据,输入只有一个数字 \(w\)。
Output
- 对于每组数据输出两行,第一行包含一个整数 \(m\),表示有 \(m\)(如果 \(m=0\),只输出一行 \(0\) 即可)个伙伴。
- 第二行包含相应的 \(m\) 个数,表示伙伴的数字。注意:小伙伴的数字必须按照升序排列。
Sample Input
42
Sample Output
3
20 26 41
Hint
- \(100\%\) 的数据,有 \(w<=2*10^9\) 。
- 来源:\(luogup4397\)
分析
-
前两天才做了个约数和定理的题,今天再出个,检验检验大家的掌握情况。
-
在学习下几个定理:
-
\(N\)的标准分解式:
\[N=\prod_{i=1}^{k} p_i^{a_i}=p_1^{a_1}*p_2^{a_2}*...*p_n^{a_n} \]- \(p_1<p_2<...<p_n\) 为质数,\(a_1,a_2,...,a_n\) 为指数,均为正整数。
-
对于上面的分解式,\(N\) 的约数个数为:\((a_1+1)*(a_2+1)*...*(a_n+1)\) 。
-
约数和定理:对上面的分解式,\(N\) 的约数和为:
- \(f(N)=(p_1^0+p_1^1+...+p_1^{a_1})*(p_2^0+p_2^1+..+p_2^{a_2}*...*(p_n^0+p_n^1+..+p_n^{a_n}))\)
-
-
此题给我们 \(N\) ,要我们求满足 \(N==f(x)\) 的 \(x\)。
-
显然 \(x=\prod_{i=1}^k p_i^{a_i}\) ,\(N=(p_1^0+p_1^1+...+p_1^{a_1})*(p_2^0+p_2^1+..+p_2^{a_2}*...*(p_n^0+p_n^1+..+p_n^{a_n}))\) ,现在我们知道 \(N\),所以我们可以枚举质数 \(p_i\) 和其指数 \(a_i\) 然后对\(N\) 进行不停拆分,拆分完一个质数就求出 \(now*=p_i^{a_i}\),当 \(N\) 拆分成 \(1\) ,则 \(now\) 就是满足条件的一个答案。
-
为了提高效率,我们可以用线性筛求出小于 \(N\) 的质数。具体实现见代码。
Code
#include <bits/stdc++.h>
#define N 100000
int Prime[N+5],cnt,w,ans,a[N+5];
bool flag[N+5];
int tot=0;
void getprime(){//线筛
for(int i=2;i<=N;i++){
if(!flag[i]) Prime[++tot]=i;
for(int j=1; i*Prime[j]<=N; j++){
flag[i*Prime[j]]=1;
if(i%Prime[j]==0) break;
}
}
}
bool isprime(int x){
if(x==1) return false;
if(x<=N) return !flag[x];//N以内的质数已经标记
for(int i=1;Prime[i]*Prime[i]<=x;i++)
if(x%Prime[i]==0) return false;
return true;
}//
void dfs(int now,int p,int x){
// w分解后为剩下now 第p个质数 x为w分解出来的pi^(ai)l连乘
if(now==1){//说明w分解完毕
a[++cnt]=x;
return;
}//now-1为质数,恰好now=(now-1)^0+(now-1)^1
if(isprime(now-1)&&now>Prime[p]) a[++cnt]=x*(now-1);
for(int i=p;Prime[i]*Prime[i]<=now;i++){//枚举下一个选哪个质数
int pi=Prime[i];//pi为Prime[i]^i
int sum=Prime[i]+1;//sum=pi^0+pi^1+..
for(;sum<=now;pi*=Prime[i],sum+=pi)
if(now%sum==0)
dfs(now/sum,i+1,x*pi);
}
}
void Solve(){
getprime();
while(scanf("%d",&w)!=EOF){
cnt=0;
dfs(w,1,1);
printf("%d\n",cnt);
std::sort(a+1,a+cnt+1);
for(int i=1;i<=cnt; i++)
printf("%d ",a[i]);
printf("\n");
}
}
int main(){
Solve();
return 0;
}
hzoi