Ela's Fitness and the Luxury Number(数学推导)

98 阅读2分钟

Problem - B - Codeforces

题目描述

题目给出 t(1t10000)t(1\le t\le 10000) 个测试用例,每个测试用例包括两个数 l,r(1lr1e18)l,r(1\le l\le r\le 1e^{18})。对于每个用例,要求输出 lrl\sim r 中满足 x%x==0x\%\sqrt{x}==0 的数 xx 的个数,数 xx 的开根需要进行下取整操作。

输入样例

5
8 19
8 20
119 121
1 100000000000000000
1234567891011 1000000000000000000

输出样例

5
6
2
948683296
2996666667

题目分析

我认为这是一道有趣的 数学推导题

首先我们对任意一个数 xx 进行打表分析。

x==1\sqrt{x}==1,则 xx 的取值范围为 1x31\le x\le 3

x==2\sqrt{x}==2,则 xx 的取值范围为 4x84\le x\le 8

x==3\sqrt{x}==3,则 xx 的取值范围为 9x159\le x\le 15

\cdots

于是我们可以找到规律:

x==y\sqrt{x}==y,则 yyx(y+1)(y+1)1y\cdot y\le x\le (y+1)(y+1)-1

我们对这一区间范围的数进行分析,发现对于每个 xx 的区间,满足 x%xx\%\sqrt{x} 的数有且仅有 33 个。在这里,我们做以下证明,对于区间 [yy,  (y+1)(y+1)1][y\cdot y,\; (y+1)(y+1)-1],我们发现 (y+1)(y+1)1=y(y+2)(y+1)(y+1)-1=y(y+2),由此可以推出满足条件的数只有 yy,  y(y+1),  y(y+2)y\cdot y,\; y\cdot (y+1),\; y\cdot (y+2) 这三个数,由此得证。

于是,对于某个数 xx,我们以 x\sqrt{x} 作为编号,若区间满足覆盖当前编号对应的区间,则对答案的贡献为 33,对于所给区间范围 l,rl,r,我们只需要判断区间的左右边界所处的编号,其之间的贡献可以直接加和,在对边界进行特判即可。

另外需要注意,sqrt()sqrt() 函数中传递的参数为 doubledouble,对于题目数据范围会有精度丢失的问题,要用手写的开根函数。

Accept代码

#include <bits/stdc++.h>
#define int long long

using namespace std;

int sqrtx(int n)
{
    int x = sqrt(n) + 0.5;
    while (x * x > n) x --;
    return x;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t; cin >> t;
    while (t --)
    {
        int l, r;
        cin >> l >> r;
        int x = sqrtx(l), y = sqrtx(r);
        int res = 3 * (y - x);
        res -= (l - x * x + x - 1) / x;
        res += (r - y * y + y) / y;
        cout << res << "\n";
    }
    return 0;
}