GDOI2007 天才的约数和

题目描述

这天周航遇到了靳泽旭。   
周航:“我是天才!”
靳泽旭:“你为什么是天才?”   
周航:“你随便告诉我一个数字,我立即可以算出它所有约数之和,以及所有约数的倒数和!”
靳泽旭:“换过来,我告诉你一个数的所有约数(包括1和该数本身)的和以及约数的倒数之和,你是天才你应该立即能推出这个数是什么!”

周航被难倒了!
现在,这个难倒了天才的题目就交到你手上了。

输入格式
输入文件包含多组测试数据(最多有3000组测试数据)。每组测试数据有三个正整数A,B1和B2,(1<=A,B1,B2<=10^9),其中A为C的约数和,而对于C的所有倒数之和B,为避免精度误差,以分数B1/B2的形式给出。
输入文件以一行“0 0 0”结束。

输出格式
对于输入的每一组数据,输出一行。该行的第一个整数N是所有满足条件的不同的C的个数。其后按照从小到大的顺序输出N个数,为所有满足条件的C。相邻两个整数之间用空格隔开,行末不要有空格。


找不到题解,出处还是在百度快照里面找到的。
百度诚不可尽信之,它骗我说这个数是不唯一的,但实际上。……
设所求数为 n。
设约数之和为 a1+a2+a3…+an。
我们知道,对于每个约数 ai,都必然存在另一个唯一的约数 n / ai,也就是说,原式还可以表示成: a1+a2+a3…+an = n / a1 + n / a2 + n / a3…+ n / an = n*( 1 / a1 + 1 / a2 + 1 / a3…+ 1 / an )。
答案已经很显然了,amazing。
但是我们的数据不一定有合法解啊(显然有反例,比如 A=2,B1=1,B2=2)所以还要把求得的 n 求一遍约数和验证是否等于题目所给的 A 。求约数和有很多方法,可以暴力搞,我用了约数和的定理:
这里写图片描述
OJ上数据超出题面,爆了 int ,按道理说是不会的。合法的时候固然不会,不合法的时候验证所求的约数和就算溢出变成负数了,那也还是不合法的,完全不影响。

#include<bits/stdc++.h>
using namespace std;

long long a,b1_,b2_;

inline void read(long long &x)
{
    x=0;int f=1;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<3)+(x<<1)+s-48;
}



inline long long check_(int x)
{
    long long res=1;//约数和。
    long long sum_,s;//s是每个质因子所属式子的和,sum_枚举每个质因子的含指数项。
    for(int i=2;i*i<=x;++i)
        if(!(x%i))
        {
            s=1LL;sum_=1LL;
            for(;!(x%i);x/=i,sum_*=1LL*i,s+=sum_);
            res*=s;
        }
    if(x!=1) res*=(x+1);
    return res;
}

int main()
{
    while(1)
    {
        read(a);read(b1_);read(b2_);
        if(!a) return 0;
        int n=a/b1_*b2_;
        if(a%b1_||check_(n)!=1LL*a) printf("0\n");//不合法有两种情况,第一种是b1根本不能整除a,第二种是倒推的约数和与数据冲突。
        else printf("1 %d\n",n);
    }
    return 0;
}

owo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值