LightOJ 1341 Aladdin and the Flying Carpet(整数拆分定理)

  分析:题目并不难理解,就是一些细节上的优化需要我们注意,我在没有优化前跑了2000多MS,优化了一些细节后就是400多MS了,之前还TLE了好几次。

  方法:将整数拆分为质因子以后,表达为这样的形式,e1*p1 + e2*p2 + .... + en*pn,整数的所有约数的个数为(1+p1)*(1+p2)*(1+pn);

  注意:当时我也在担心,题目中要求我们的分解成的两个数不能相等,但是当我们求出约数总数以后直接除了2(因为我们只需要一半),没有特殊处理相等的情况,会不会出错? 其实不会,我们这个是整除2,巧妙的把中间的约数挖去了,举个例子吧,4的约数有(1,2,4)三个,这里能用的只有(1,4)这一组,3/2 = 1,正好是正确答案。这里是一个细节,应该注意到。

  具体的一些细节表示在下面的代码里:

  

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define LL long long///数据比较强,建议LL
#define maxn 1000010///质因子,所有sqrt(1^12) = 1^6就够了
LL is_prime[maxn],prime[maxn],cnt;
void make_prime()
{
    memset(is_prime,1,sizeof(is_prime));
    is_prime[1] = 0;
    cnt = 0;
    for(int i = 2; i <= maxn; i++)
    {
        if(is_prime[i])
        {
            prime[cnt++] = i;///建议在这就记数
            for(int j = 2*i; j <= maxn; j += i)
                is_prime[j] = 0;
        }
    }
}
LL slove(LL num)
{
    LL sum = 1;
    for(int i = 0; i < cnt && prime[i]*prime[i] <= num; i++)///质因子一定满足平方小于等于原数
    {
        ///尽量使用乘积的形式,这里不会溢出,而根号有精度或者其他问题,当时我开了根号居然是超时……
        int tot = 0;
        if(num == 1) break;///及时退出
        while(num % prime[i] == 0)
        {
            num /= prime[i];
            tot++;
        }
        sum *= (tot+1);
    }
    if(num > 1) sum *= 2;
    return sum;
}
int main()
{
    int t,ca = 0;
    LL a,b;
    make_prime();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&a,&b);
        if(a < b*b)///注意这个小小的判断,它会节省很多时间。
        {
            printf("Case %d: 0
",++ca);
            continue;
        }
        LL num = slove(a);
        num /= 2; /// 整除
        for(LL i = 1; i < b; i++)///我们还要去掉不满足的解
        {
            if(a % i == 0) num--;
        }
        printf("Case %d: %lld
",++ca,num);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jifahu/p/5585219.html