找伙伴

找伙伴(数论 \(\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\)

分析

  • 前两天才做了个约数和定理的题,今天再出个,检验检验大家的掌握情况。

  • 在学习下几个定理:

    1. \(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\) 为指数,均为正整数。
    2. 对于上面的分解式,\(N\) 的约数个数为:\((a_1+1)*(a_2+1)*...*(a_n+1)\)

    3. 约数和定理:对上面的分解式,\(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;
}
posted @ 2020-08-01 12:08  ♞老姚♘  阅读(173)  评论(0编辑  收藏  举报