ACM学习历程—FZU2191完美的数字(数学)

Description

Bob是个很喜欢数字的孩子,现在他正在研究一个与数字相关的题目,我们知道一个数字的完美度是 把这个数字分解成三个整数相乘A*A*B(0<A<=B)的方法数,例如数字80可以分解成1*1*80,2*2*20 ,4*4*5,所以80的完美度是3;数字5只有一种分解方法1*1*5,所以完美度是1,假设数字x的完美度为d(x),现在给定a,b(a<=b),请你帮Bob求出

S,S表示的是从a到b的所有数字的流行度之和,即S=d(a)+d(a+1)+…+d(b)。

Input

输入两个整数a,b(1<=a<=b<=10^15)

Output

输出一个整数,表示从a到b的所有数字流行度之和。

Sample Input

1 80

Sample Output

107

题目要求a到b区间内,d(i)的和。

而d(i)表示i能拆分成A*A*B形式的种数,A<=B

首先直接要求i的拆分需要暴力枚举的话,复杂度是很大的。

于是考虑到i = A*A*B的话,对于一组满足条件的(A, B)就需要对d(i)++,d(i)初值为0.

但是这样的话还是需要从小到大枚举A,并枚举B,求出所有区间内的d(i)。

但是题目要求的是和。

这样的话有一部是可以优化就是我们最后求的和就是每次++的和,因为d初值为0。

那么我枚举到某个A的时候,有多少个满足条件的B,就需要++多少次。也就是只需要得到一个上界和下届,一减就得到了。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <algorithm>
#define LL long long

using namespace std;

const int maxN = 1e5;
LL a, b;

LL myMax(LL x, LL y)
{
    return x > y ? x : y;
}

void work()
{
    LL x, y, ans = 0;
    for (LL k = 1; k <= maxN && k*k*k <= b; ++k)
    {
        if (a%(k*k) == 0)
            x = a/(k*k);
        else
            x = a/(k*k)+1;
        x = myMax(x, k);
        y = b/(k*k);
        ans += y-x+1;
    }
    printf("%I64d
", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%I64d%I64d", &a, &b) != EOF)
    {
        work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/andyqsmart/p/4795390.html