题目描述
题目给出 个测试用例,每个测试用例包括两个数 。对于每个用例,要求输出 中满足 的数 的个数,数 的开根需要进行下取整操作。
输入样例
5
8 19
8 20
119 121
1 100000000000000000
1234567891011 1000000000000000000
输出样例
5
6
2
948683296
2996666667
题目分析
我认为这是一道有趣的 数学推导题。
首先我们对任意一个数 进行打表分析。
若 ,则 的取值范围为 ;
若 ,则 的取值范围为 ;
若 ,则 的取值范围为
于是我们可以找到规律:
若 ,则 。
我们对这一区间范围的数进行分析,发现对于每个 的区间,满足 的数有且仅有 个。在这里,我们做以下证明,对于区间 ,我们发现 ,由此可以推出满足条件的数只有 这三个数,由此得证。
于是,对于某个数 ,我们以 作为编号,若区间满足覆盖当前编号对应的区间,则对答案的贡献为 ,对于所给区间范围 ,我们只需要判断区间的左右边界所处的编号,其之间的贡献可以直接加和,在对边界进行特判即可。
另外需要注意, 函数中传递的参数为 ,对于题目数据范围会有精度丢失的问题,要用手写的开根函数。
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;
}